Suppose you're given a list xs :: [a]
and function f :: Monad m => a -> m b
. You want to apply the function f
to each element of xs
, yielding a list of actions, then sequence these actions. Here is how I would go about constructing a function, call it mapM
, that does this. In the base case, xs = []
is the empty list, and we simply return []
. In the recursive case, xs
has the form x : xs
. First, we want to apply f
to x
, giving the action f x :: m b
. Next, we want recursively call mapM
on xs
. The result of performing the first step is a value, say y
; the result of performing the second step is a list of values, say ys
. So we collect y
and ys
into a list, then return them in the monad:
mapM :: Monad m => (a -> m b) -> [a] -> m [b]
mapM f [] = return []
mapM f (x : xs) = f x >>= \y -> mapM f ys >>= \ys -> return (y : ys)
Now we can map a function like print
, which returns an action in the IO
monad, over a list of values to print: mapM print [1..10]
does precisely this for the list of integers from one through ten. There is a problem, however: we aren't particularly concerned about collecting the results of printing operations; we're primarily concerned about their side effects. Instead of returning y : ys
, we simply return ()
.
mapM_ :: Monad m => (a -> m b) ->[a] -> m ()
mapM_ f [] = return ()
mapM_ f (x : xs) = f x >> mapM_ f xs
Note that mapM
and mapM_
can be defined without explicit recursion using the sequence
and sequence_
functions from the standard library, which do precisely what their names imply. If you look at the source code for mapM
and mapM_
in Control.Monad
, you will see them implemented that way.