Pavel
Pavel

Reputation: 138

How binding works in function monads in Haskell?

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

Answers (3)

Will Ness
Will Ness

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

willeM_ Van Onsem
willeM_ Van Onsem

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

Mark Seemann
Mark Seemann

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

Related Questions