我对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
为什么?我该如何解决这个问题?
答案 0 :(得分:17)
在addStuff'
中,您可以撰写(*2) w
和(+10) w
。这些分别相当于w*2
和w+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 -> Int
为m 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) Int
或Int -> Int
,而不是((->) Int)
。