关于函数monad

chi*_*k10 9 monads haskell

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

instance Monad ((->) r) where
     return x = \_ -> x
     h >>= f = \w -> f (h w) w
Run Code Online (Sandbox Code Playgroud)

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

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

(return 3) :: ((->) Int)
Run Code Online (Sandbox Code Playgroud)

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

addStuff = do
           a <- (*2)
           b <- (+10)
           return (a+b)
Run Code Online (Sandbox Code Playgroud)

然后将此函数转换为

addStuff' w = (*2)  w >>= (\a ->
              (+10) w >>= (\b ->
              return (a+b) ))
Run Code Online (Sandbox Code Playgroud)

我查看了新功能的类型

addStuff :: (Monad m, Num (m b), Num b) => m b -> m b 
Run Code Online (Sandbox Code Playgroud)

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

sep*_*p2k 17

addStuff'你写(*2) w(+10) w.这些分别相当于w*2w+10.所以addStuff'相当于:

addStuff' w = w*2 >>= \a ->
              w+10 >>= \b ->
              return (a+b)
Run Code Online (Sandbox Code Playgroud)

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

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

addStuff' = (*2) >>= \a ->
            (+10) >>= \b ->
            return (a+b)
Run Code Online (Sandbox Code Playgroud)

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

( (*2) >>= (+10) ) 3 
Run Code Online (Sandbox Code Playgroud)

操作员>>=有类型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)
Run Code Online (Sandbox Code Playgroud)

((->) Int)善良* -> *- 价值的类型必须有种类*.

或以不同的方式接近这一点:return 3已经输入m Int了一些m(仍然假设所有整数文字具有类型Int为简单起见).所以,如果m`((->) Int),那return 3将是((->) Int) IntInt -> Int不是((->) Int).