为什么我需要在 fmap 的定义中再次调用构造函数,即使我没有应用 f 参数?

Why do I need to call the constructor again in the definition of fmap even when I don't apply the f argument?

我不知道为什么下面的 fmap _ a = a 是非法的。这是代码:

data Sum a b = First a | Second b

instance Functor (Sum a) where
  fmap f (Second b) = Second (f b)
  fmap _ (First a)  = First a
  fmap _ a          = a  -- Why can't I do this instead?

另一个问题是,这是否会影响性能或仅在编译时发生?

您需要调用构造函数 anew 来创建一个 new 值,因此它的类型将与您的不同已经开始了。

fmap ::   (b -> c) ->    Sum a b  -> Sum a c
fmap (f :: b -> c) ::    Sum a b  -> Sum a c
fmap (f :: b -> c) (x :: Sum a b) -> Sum a c

                 a ::     a               a ::     a
           First a :: Sum a b       First a :: Sum a c

                 b ::       b             c ::       c
          Second b :: Sum a b      Second c :: Sum a c

给定 a :: aFirst a 的类型 Sum a ttFirst a 出现的上下文决定。等号两边的两个 First a 定义了两个不同的值,每个都有自己的类型。使用右侧的变量 a,它仍然引用与左侧相同的类型 Sum a b 的值。但是根据 fmap.

我们需要不同的类型

关于性能:在编译过程的后期,当 GHC 删除了大部分类型信息时,它会尽力注意何时像这样重建值。这一步捕获了很多情况,但不是全部;有时代码会以这样一种方式进行转换,以至于重构不再明显。

你不能这样做的原因是因为 fmap 的结果类型取决于 f 的结果类型,而表达式 a 则不然。也就是说,你没有约束 f b ~ a.