I'm on the I/O chapter of Real World Haskell. Monads aren't discussed in the book for another 7 chapters. Which is to say, my understanding of I/O is, at best, incomplete.
Right now I am trying to comprehend the mapM function. As I understand it, the function "executes" each element in the list which must be an "action" (I开发者_C百科O monad).
What doesn't make sense is this example. Why does mapM return a different result than map for the same arguments?
Prelude> map (\x -> [x]) [0, 1, 2] [[0],[1],[2]] Prelude> mapM (\x -> [x]) [0, 1, 2] [[0,1,2]]
As I understand it, the function "executes" each element in the list which must be an "action" (IO monad).
That's true for IO, but in your code example you don't use the IO monad, you use the list monad (the function you give to mapM returns a list ([x]
), not an IO).
mapM
is defined as mapM f as = sequence (map f as)
. If f returns an IO this means that for each element in the list it constructs an IO by applying f to the element. It then turns the list of IOs that map returns into an IO "containing" a list using sequence (so when you execute the IO, you get back a list containing non-IO values).
For lists it means that it creates a list of lists by applying f
to each element of as
. It then uses sequence
to create a list of lists which contains all possible ways to take one element of each list in the lists of lists (e.g. sequence [[1,2],[3,4]]
returns [[1,3],[1,4],[2,3],[2,4]]
).
It's probably worth making clear that these two snippets are not 'analogous' and you shouldn't expect related results. In particular, a 'monadic' version of
map (\x -> [x]) [0, 1, 2]
is
mapM (\x -> return [x]) [0, 1, 2]
Note the extra return
.
In general, return (map f x)
is the same as mapM (return . f) x
.
This is because for the list monad, x >>= f
'flattens' the result of applying f
to x
. When you left out the return
the results of applying \x -> [x]
were being flattened into the result. Having an extra return
cancels out the extra flattening.
精彩评论