The List monad has return x = [x]
. So why in the following example is the result not [(["a", "b"], [2, 3])]
?
> pairs a b = do { x <- a; y <- b; return (x, y)}
> pairs ["a", "b"] [2,3]
[("a",2),("a",3),("b",2),("b",3)]
The List monad has return x = [x]
. So why in the following example is the result not [(["a", "b"], [2, 3])]
?
> pairs a b = do { x <- a; y <- b; return (x, y)}
> pairs ["a", "b"] [2,3]
[("a",2),("a",3),("b",2),("b",3)]
In general,
means, in pseudocode,
whatever the
"for ... in ... do"
and"yield"
mean for the particular monad. More formally, it's(
(<$>)
is an alias forfmap
).For the
Identity
monad, wherereturn a = Identity a
andjoin (Identity (Identity a)) = Identity a
, it is indeedFor the list monad though,
"for"
meansforeach
, becausereturn x = [x]
andjoin xs = concat xs
:and so,
Monadic bind satisfies
ma >>= k = join (fmap k ma)
wherema :: m a, k :: a -> m b
for aMonad m
. Thus for lists, wherefmap = map
, we havema >>= k = join (fmap k ma) = concat (map k ma) = concatMap k ma
:which is exactly what nested loops do. Thus
Loop unrolling is what nested loops do ⁄ are, and nested computations are the essence of Monad.
It is also interesting to notice that
which goes to the heart of the "nested loops ⁄ yield" analogy. Monads are higher order monoids, "what's the problem?"
Let us first analyze and rewrite the function
pairs
:Here we thus have a monad. We use
do
as syntactical sugar. But the compiler rewrites this to:Or in a more canonical form:
Now the list monad is defined as:
So we have written:
So we thus take as input two lists
a
andb
, and we perform aconcatMap
ona
with as function(\x -> concatMap (\y -> [(x, y)]) b)
. In that function we perform anotherconcatMap
onb
with as function\y -> [(x, y)]
.So if we evaluate this with
pairs ["a", "b"] [2,3]
we get: