关于函数monad

问题描述 投票:10回答:1

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

为什么?我该如何解决?

haskell monads
1个回答
18
投票

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。为简单起见,假设此代码中的所有数字均为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)

© www.soinside.com 2019 - 2024. All rights reserved.