11

我对函数 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 

这是为什么?我该如何解决?

4

1 回答 1

19

addStuff'你写(*2) w(+10) w。它们分别相当于w*2w+10。所以addStuff'等价于:

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

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

消除do符号时,左操作数>>=应与 的右操作数完全相同<-。同样消除do符号不会向函数添加任何参数。所以正确的重写应该是这样的:

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

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

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

运算符>>=具有类型m a -> (a -> m b) -> m b。为简单起见,我们假设这段代码中的所有数字都有 type Int,那么你的左操作数有 typeInt -> Intm Intif mis (->) Int。因此,对于某些类型b,正确的操作数应该有 typeInt -> ((->) Int) b或者,更易读,Int -> Int -> b. 它实际上具有的类型是Int -> Int. 因此,您的表达方式错误。

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

((->) Int)has kind * -> *- 值的类型必须有 kind *

或者以不同的方式处理这个问题:return 3m Int一些m类型(为了简单起见,仍然假设所有整数文字都有类型Int)。所以如果m((->) Int),类型return 3将是((->) Int) IntInt -> Int,不是((->) Int)

于 2013-01-20T23:18:25.540 回答