Reputation: 73
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
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
Reputation: 4249
Problem to make the last monadic:
addStuff = (*2) >>= \a ->
(+10) >>= \b ->
return (a + b)
Upvotes: 3