关于函数monad

时间:2013-01-20 23:07:39

标签: haskell monads

我对monad函数有些困惑。函数monad定义如下:

instance Monad ((->) r) where
     return x = \_ -> x
     h >>= f = \w -> f (h w) w

我尝试通过编写绑定操作来解决它:

( (*2) >>= (+10) ) 3 

(return 3) :: ((->) Int)

但它造成了错误。我还尝试将函数AddStuff重写为绑定操作。

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

然后将此功能转换为

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

我检查新功能的类型,见

addStuff :: (Monad m, Num (m b), Num b) => m b -> m b 

为什么?我该如何解决这个问题?

1 个答案:

答案 0 :(得分:17)

addStuff'中,您可以撰写(*2) w(+10) w。这些分别相当于w*2w+10。所以addStuff'等同于:

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

以这种方式编写应该很明显,这里>>=的左操作数是数字,而不是函数。这就是为什么推断类型告诉你,你的函数只适用于monad的数字。

取消do表示法时,>>=的左操作数应与<-的右操作数完全相同。同样消除do表示法不会向函数添加任何参数。所以正确的重写看起来像这样:

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

至于为什么你早期的代码不起作用:

( (*2) >>= (+10) ) 3 

运营商>>=的类型为m a -> (a -> m b) -> m b。为简单起见,我们假设此代码中的所有数字都具有类型Int,如果Int -> Intm Int,则左操作数的类型为m(->) Int。因此,对于某些类型b,右操作数应该具有类型Int -> ((->) Int) b,或者更可读的是Int -> Int -> b。它实际拥有的类型是Int -> Int。因此,你的表达方式是错误的。

(return 3) :: ((->) Int)

((->) Int)* -> *种类 - 值的类型必须有*种类。

或者以不同的方式处理:return 3对于某些m Int具有类型m(为了简单起见,仍假设所有整数文字都具有类型Int)。因此,如果m`((->) Int),则return 3的类型将为((->) Int) IntInt -> Int,而不是((->) Int)