5

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.

3 Answers 3

7

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 
Sign up to request clarification or add additional context in comments.

Comments

3

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

Comments

2

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.