I more or less wrapped my head around monads, but i can't deduct how expression
(>>=) id (+) 3
evaluates to 6. It just seems the expression somehow got simplified to
(+) 3 3
but how? How is 3 applied twice? Could someone explain what is happening behind the scenes ?
2 Answers 2
This follows from how >>= is defined for the ((->) r) types:
(f =<< g) x = f (g x) x
Thus
(>>=) id (+) 3
=
(id >>= (+)) 3
=
((+) =<< id) 3
=
(+) (id 3) 3
=
3 + 3
see the types:
> :t let (f =<< g) x = f (g x) x in (=<<)
let (f =<< g) x = f (g x) x in (=<<)
:: (t1 -> (t2 -> t)) -> (t2 -> t1) -> (t2 -> t)
> :t (=<<)
(=<<) :: Monad m => (a -> m b) -> m a -> m b
The types match with
t1 ~ a
(t2 ->) ~ m -- this is actually ((->) t2)`
t ~ b
Thus the constraint Monad m here means Monad ((->) t2), and that defines the definition of =<< and >>= which get used.
If you want to deduce the definition from the type,
(>>=) :: Monad m => m a -> (a -> m b) -> m b
m ~ ((->) r)
(>>=) :: (r -> a) -> (a -> r -> b) -> (r -> b)
(>>=) f g r = b
where
a = f r
rb = g a
b = rb r
which after the simplification becomes the one we used above.
And if you want to understand it "with words",
(=<<) :: (Monad m, m ~ ((->) r)) => (a -> m b) -> m a -> m b
(f =<< g) x = f (g x) x
gis a "monadic value" that "can compute" an "a", represented asr -> af acalculates a "monadic value" that "can compute" a "b", represented asr -> b,- thus
\x -> f (g x) xis a monadic value that "can compute" a "b", given an "r".
So these "non-monadic functions" are, in fact, monadic values, which happen to be functions.
Thus in your example, g = id, f = (+), and
idis a "monadic value" that "can compute" an "a", ana -> a(+) acalculates a "monadic value" that "can compute" a "b", ana -> b, whichbis actually also ana,- thus
\x -> (+) (id x) xis a monadic value that "can compute" an "a", given an "a":
(>>=) id (+)
=
((+) =<< id)
=
\x -> (+) (id x) x
=
\x -> (+) x x
5 Comments
=<<, but perhaps I am missing something?(=<<) :: Monad m => (a -> m b) -> m a -> m b also aligns nicely with the other types, of (<$>) and (<*>), all ending with the m a -> m b.r on the right of -> is usually for "result", here on the left of -> I use it as a reminder of "reader" although of course the whole type is a "reader" from an "environment" so it probably should have been e instead (but e is also often an "error" as in e.g. Either e a). a, t, etc are for the more generic types.Adding some colour to Will's excellent answer.
If we look at the source, we have this:
instance Monad ((->) r) where f >>= k = \ r -> k (f r) r
If we rearrange the input expression slightly, we get (id >>= (+)) 3. This now resembles the form shown above. Now fitting the input into the above 'template', we can rewrite the input as \ r -> (+) (id r) r
This is the same expression we arrived at for the final evaluation i.e. (+) (id 3) 3
(+) :: a -> m awherem ~ (->) awhich is a monad. (The fact that we needNum afor(+)does not change this.) Also,id :: m afor the same monad. So, we can haveid >>= (+) :: m a, which is a functiona -> aand can be applied to3.