在Bartosz Milewski的程序员类别理论中,Milewski编写了以下代码来为Writer monad定义return和'fish'运算符(Kleisli类别中的组合)。
return :: a -> Writer a
return x = (x, "")
(>=>) :: (a -> Writer b) -> (b -> Writer c) -> (a -> Writer c)
m1 >=> m2 = \x ->
let (y, s1) = m1 x
(z, s2) = m2 y
in (z, s1 ++ s2)
然后他继续定义fmap
如下:
fmap f = id >=> (\x -> return (f x))
我很难理解这里如何使用id
函数。 fish运算符的第一个参数显然是(a -> Writer b)
,但id具有类型签名a -> a
。
这是我理解中的错误还是缺陷?用id
替换return
对我来说更有意义。
答案 0 :(得分:2)
不要忘记通用量化。
鱼(>=>)
对于任何 (a -> Writer b) -> .....
和a
都有b
类型。
id
对于任何 a -> a
都有a
类型。
因此,特别是,对于任何(Writer b -> Writer b) -> ...
,鱼类也都有b
类型(只需将a = Writer b
作为特例)。
此外,id
还有Writer b -> Writer b
类型(再次,作为特例)。
这里的“技巧”是使用统一“合并”这两种类型。
我们首先要求(a -> Writer b) = (a' -> a')
,然后推断a = a'
和Writer b = a'
。从这里,我们可以看到这两种类型可以统一,因此传递参数没有矛盾。
(另请注意,我们在此处将a
的{{1}}重命名为id
以避免与其他a'
混淆鱼类