What is the difference between the functions liftM and mapM?
They aren't really related. I'll try to explain what each of them does. I assume you have a basic understanding of what a monad is.
liftM :: Monad m => (a -> b) -> (m a -> m b)
lets you use an ordinary function in a monad. It takes a function a -> b
, and turns it into a function m a -> m b
, that does exactly the same thing as the original function, but does it in a monad. The resulting function doesn't "do" anything to the monad (it can't, because the original function didn't know it was in a monad). For example:
main :: IO ()
main = do
output <- liftM ("Hello, " ++) getLine
putStrLn output
The function ("Hello, " ++) :: String -> String
prepends "Hello, " to a string. Passing it to liftM
creates a function of type IO String -> IO String
-- now you have a function that works in the IO monad. It doesn't do any IO, but it can take an IO action as input, and produces an IO action as output. Therefore, I can pass getLine
as input, and it will call getLine
, prepend "Hello, " to the front of the result, and return that as an IO action.
mapM :: Monad m => (a -> m b) -> [a] -> m [b]
is quite different; note that unlike liftM
, it takes a monadic function. For example, in the IO monad, it has type (a -> IO b) -> [a] -> IO [b]
. It is very much like the ordinary map
function, only it applies a monadic action to a list, and produces a result list wrapped in a monadic action. For example (a pretty bad one):
main2 :: IO ()
main2 = do
output <- mapM (putStrLn . show) [1, 2, 3]
putStrLn (show output)
This prints:
1
2
3
[(),(),()]
What it is doing is iterating over the list, applying (putStrLn . show)
to each element in the list (having the IO effect of printing out each of the numbers), and also transforming the numbers into the ()
value. The resulting list consists of [(), (), ()]
-- the output of putStrLn
.