将语法转换为>> = with(( - >)r)monad

时间:2014-12-19 05:56:04

标签: haskell functional-programming monads

在页面http://en.wikibooks.org/wiki/Haskell/do_Notation上,有一种非常方便的方法可以将do语法转换为功能形式(我的意思是,使用>> =)。它适用于很多情况,直到我遇到一段涉及函数monad的代码(( - >)r)

代码是

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

这相当于定义

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

现在,如果我使用方便的方式重写do部分,我得到

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

给出了编译错误。我知道a,b是Int(或其他类型的Num),所以最后一个函数(\ b - &gt; a + b)的类型为Int - &gt; Int,而不是Int - &gt; Int - &gt;中间体

但这是否意味着并不总是从do转换为&gt;&gt; =?有没有解决这个问题?或者我只是错误地使用规则?

2 个答案:

答案 0 :(得分:3)

制作最后一个monadic的问题:

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

答案 1 :(得分:1)

(你已经回答了)正确的表达式必须在最后一行使用return

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

(详细说明,澄清),即return是monad定义的一部分,而不是do符号。

替换((->) r) monad的实际定义,它相当于

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)

正如所料。所以一般来说,对于函数来说,

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

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

(除了每个标识符a,b,...,n不应出现在相应的函数调用中,因为let绑定是递归的,而do绑定不是。)

以上do代码也正是在Control.Monad中定义liftM2的原因:

> liftM2 (+) (*2) (+10) 100
310
任何liftM_N

N都可以使用liftMap进行编码:

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

liftMfmap的monadic等价物,其函数为(.),所以

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

因为ap f g x = f x (g x)代表函数(a.k.a。 S -combinator)。