Bo-Xiao Zheng
Bo-Xiao Zheng

Reputation: 73

transform do syntax to >>= with ((->) r) monad

On the page http://en.wikibooks.org/wiki/Haskell/do_Notation, there's a very handy way to transform the do syntax with binding to the functional form (I mean, using >>=). It works well for quite a few case, until I encountered a piece of code involving functions as monad ((->) r)

The code is

addStuff :: Int -> Int  
addStuff = do  
    a <- (*2)  
    b <- (+10)  
    return (a+b)

this is equivalent as define

addStuff = \x -> x*2+(x+10)

Now if I use the handy way to rewrite the do part, I get

addStuff = (*2) >>= \a ->
           (+10) >>= \b ->
           a + b

which gives a compiling error. I understand that a, b are Int (or other types of Num), so the last function (\b -> a + b) has type Int -> Int, instead of Int -> Int -> Int.

But does this mean there's not always a way to transform from do to >>= ? Is there any fix to this? Or I'm just using the rule incorrectly?

Upvotes: 1

Views: 148

Answers (2)

Will Ness
Will Ness

Reputation: 71119

(you've already been answered, that) The correct expression must use return on the last line:

addStuff = (*2) >>= \a ->
           (+10) >>= \b ->
           return (a + b)

(expounding on that, for some clarification) i.e. return is part of a monad definition, not of do notation.

Substituting the actual definitions for ((->) r) monad, it is equivalent to

addStuff x 
  = ((\a -> (\b -> return (a + b)) =<< (+10) ) =<< (*2) )  x
  = (\a -> (\b -> return (a + b)) =<< (+10) )  (x*2)  x
  = ( (\b -> return ((x*2) + b)) =<< (+10) )  x
  = (\b -> return ((x*2) + b))  (x+10)  x
  = return ((x*2) + (x+10))  x
  = const  ((x*2) + (x+10))  x
  =         (x*2) + (x+10)

as expected. So in general, for functions,

do { a <- f ; b <- g ; ... ; n <- h ; return r a b ... n }

is the same as

\ x -> let a = f x in let b = g x in ... let n = h x in r a b ... n

(except that each identifier a,b,...,n shouldn't appear in the corresponding function call, because let bindings are recursive, and do bindings aren't).

The above do code is also exactly how liftM2 is defined in Control.Monad:

> liftM2 (+) (*2) (+10) 100
310

liftM_N for any N can be coded with the use of liftM and ap:

> (\a b c -> a+b+c) `liftM` (*2) `ap` (+10) `ap` (+1000) $ 100
1410

liftM is the monadic equivalent of fmap, which for functions is (.), so

(+) `liftM` (*2) `ap` (+10) $ x 
  = (+) . (*2) `ap` (+10) $ x 
  = ((+) . (*2)) x ( (+10) x ) 
  = (x*2) + (x+10)

because ap f g x = f x (g x) for functions (a.k.a. S-combinator).

Upvotes: 1

ja.
ja.

Reputation: 4249

Problem to make the last monadic:

addStuff = (*2) >>= \a ->
           (+10) >>= \b ->
           return (a + b)

Upvotes: 3

Related Questions