2014-12-19 17 views
1

在页面http://en.wikibooks.org/wiki/Haskell/do_Notation上,有一种非常方便的方法来将do语法绑定到函数形式(我的意思是使用>> =)。它非常适用不少情况下,直到我遇到了一段代码,涉及职能单子(( - >)R)将语法转换为>> = with(( - >)r)monad

的代码是

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

这相当于为定义

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

现在,如果我用方便的方法重写做兼职,我得到

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

这给编译埃罗河我知道a,b是Int(或其他类型的Num),所以最后一个函数(\ b - > a + b)的类型是Int - > Int,而不是Int - > Int - > Int。

但是,这是否意味着并不总是有一种方法可以从do转换为>> =?有没有解决这个问题?或者我只是不正确地使用规则?

回答

3

问题做出最后的单子:

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

我看到这个作品。但重点可能不是格式,而是将Int包裹到(Int - > Int)的返回值。不管怎么说,还是要谢谢你! – 2014-12-19 06:16:38

+0

是的,你是对的。也感谢你。 – 2014-12-19 06:24:06

1

(你已经有了答案,那)正确的表达必须在最后一行用return

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

(对此进行阐述,作一些澄清)return是monad定义的一部分,而不是do表示法。

代的实际定义为((->) r)单子,就相当于

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代码也正是liftM2在Control中的定义。单子:

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

liftM_N任何N可以通过使用的liftMap进行编码:

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

liftMfmap的一元当量,这对于功能是(.),所以

(+) `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) for functions(aka S -combinator)。

+0

谢谢!这是很多有用的信息。 – 2014-12-20 18:52:00

相关问题