Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

map versus mapM behavior

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" (IO 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]]
like image 743
titaniumdecoy Avatar asked Jun 29 '10 00:06

titaniumdecoy


2 Answers

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]]).

like image 150
sepp2k Avatar answered Sep 17 '22 03:09

sepp2k


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.

like image 39
sigfpe Avatar answered Sep 20 '22 03:09

sigfpe