用id定义fmap并返回

时间:2018-06-06 15:36:23

标签: haskell functional-programming monads functor

在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对我来说更有意义。

1 个答案:

答案 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'混淆鱼类