Reputation: 138
From learn you a haskell: http://learnyouahaskell.com/for-a-few-monads-more
Monad instance for function is this:
instance Monad ((->) r) where
return x = \_ -> x
h >>= f = \w -> f (h w) w
I am having trouble understanding the output of the following:
import Control.Monad.Instances
addStuff :: Int -> Int
addStuff = do
a <- (*2)
b <- (+10)
return (a+b)
addStuff 3
returns 19. Book says 3 gets passed as parameters to both (*2)
and (+10)
. How?
From h >>= f = \w -> f (h w) w
, it seems like (h w)
is getting bound to a or b.
So, why 6 is not being passed in (+10)?
My understanding of f
here is that when (*2)
is h
, f
is the last 2 lines of addStuff
. When (+10)
is h
, f
is the last line (in this case the return statement) of addStuff
.
Upvotes: 5
Views: 309
Reputation: 71119
Passing the updated argument between the computation steps (which would thus be serving a role of a state) is the job of another monad, namely the State monad.
The function aka Reader monad is simpler than that, does less work:
-- (return x) w = x
-- (h >>= f) w = f (h w) w
(h >>= (\a -> g >>= (\b -> return (f a b)))) w
=
(\a -> g >>= (\b -> return (f a b))) (h w) w
=
(g >>= (\b -> return (f (h w) b))) w
=
(\b -> return (f (h w) b))) (g w) w
=
return (f (h w) (g w)) w
=
f (h w) (g w)
Thus the input argument w
is passed unchanged into both (by extension, all) the computation steps. Or in the specific case you ask about,
liftM2 (+) ( *2) ( +10) w
=
(+) (w*2) (w+10)
liftM2
function is equivalent to the do
block that you show,
liftM2 f h g =
do {
a <- h ;
b <- g ;
return (f a b) }
=
h >>= (\ a ->
g >>= (\ b -> return (f a b) ))
in any monad.
Upvotes: 2
Reputation: 477684
Let us first desugar the do
block [Haskell'10 report]:
addStuff = do
a <- (*2)
b <- (+10)
return (a+b)
is equivalent to:
addStuff = (*2) >>= \a -> ((+10) >>= \b -> return (a + b))
The inner bind expression ((+10) >>= \b -> return (a + b)
), can thus be converted, with the bind definition to:
\w -> (\b -> return (a + b)) ((+10) w) w
and if we substitute return
with const
, we thus obtain:
\w -> (const . (a+)) ((+10) w) w
We thus have a function that takes as input w
, and then calls const . (a+)
on (w+10)
and w
, so it will ignore the last w
. Semantically it is equivalent to:
(a+) . (+10)
So now our addStuf
is equivalent to:
addStuff = (*2) >>= \a -> ((a+) . (+10))
and if we now use the definition for the bind operator again, we see:
\w -> (\a -> ((a+) . (+10))) ((*2) w) w
or shorter:
\w -> (\a -> ((a+) . (+10))) (w*2) w
We can now substitue a
with (w*2)
and obtain:
\w -> ((w*2)+) . (+10)) w
So our addStuf
is equivalent to:
addStuff w = (w*2) + (w+10)
or more simple:
addStuff w = 3*w + 10
Upvotes: 7
Reputation: 233427
Haskell do
notation is syntactic sugar for a series of >>=
bindings; in this case, for something like this:
addStuff = (*2) >>= (\a -> (+10) >>= (\b -> return (a + b)))
Upvotes: 3