无法将类型“ a”与“ a1”匹配

时间:2018-10-26 04:21:38

标签: haskell functor

我正在第一章第16章的Haskell编程中进行练习。问题是要我们为数据类型编写Functor定义:

{-# LANGUAGE FlexibleInstances #-}
newtype Flip f a b = Flip (f b a) deriving (Eq, Show)
newtype K a b = K a
instance Functor (Flip K a) where
  fmap = undefined

这是我的尝试:

{-# LANGUAGE FlexibleInstances #-}
newtype Flip f a b =
  Flip (f b a)
  deriving (Eq, Show)

newtype K a b =
  K a

-- instance Functor (K a) where
-- fmap _ (K a) = K a

instance Functor (Flip K a) where
  fmap _ (Flip (K a)) = Flip (K a)

但无法编译:

chapEx2.hs:17:25: error:
    • Couldn't match type ‘a1’ with ‘b’
      ‘a1’ is a rigid type variable bound by
        the type signature for:
          fmap :: forall a1 b. (a1 -> b) -> Flip K a a1 -> Flip K a b
        at chapEx2.hs:17:3-6
      ‘b’ is a rigid type variable bound by
        the type signature for:
          fmap :: forall a1 b. (a1 -> b) -> Flip K a a1 -> Flip K a b
        at chapEx2.hs:17:3-6
      Expected type: Flip K a b
        Actual type: Flip K a a1
    • In the expression: Flip (K a)
      In an equation for ‘fmap’: fmap f (Flip (K a)) = Flip (K a)
      In the instance declaration for ‘Functor (Flip K a)’
    • Relevant bindings include
        a :: a1 (bound at chapEx2.hs:17:19)
        f :: a1 -> b (bound at chapEx2.hs:17:8)
        fmap :: (a1 -> b) -> Flip K a a1 -> Flip K a b
          (bound at chapEx2.hs:17:3)
   |
17 |   fmap f (Flip (K a)) = Flip (K a)
   |                         ^^^^^^^^^^

有人可以解释该错误信息吗?我只是对错误消息感到困惑:

  1. 为什么编译器将Actual type推论为Flip K a a1而不是Flip K a b
  2. 为什么编译器会麻烦匹配K的第三个参数?类型K的定义只有一个a但没有bb仅出现在数据类声明的左侧(=的左侧符号),而不是=的类型类声明(newtype K a b = K a符号的右侧)。
  3. 为什么不能将Flip (K a)更改为Flip x
  4. 我发现fmap f (Flip (K a)) = Flip (K (f a))可以编译,有什么区别?

1 个答案:

答案 0 :(得分:2)

问题1

您犯了一个错误。 Flip意味着您需要映射K first 参数:

instance Functor (Flip K a) where
  fmap f (Flip (K a)) = Flip (K (f a))

问题2

有充分的理由。其中之一是给类型 phantom 参数(维护程序不变性或指导实例解析)非常有用。如果编译器只是忽略它们,那么这些技术将毫无价值。 (请注意:您可以在需要时忽略它们,Data.Coerce提供了一些高级工具来执行此操作。您可能还没有准备好进行强制转换。)

另一个原因是,要弄清楚哪些类型与其他类型相等将变得非常困难,因为您必须查看每种类型的详细信息。可能还有更多原因。

一旁

FlexibleInstances似乎很尴尬,并且在这里受到限制。这是我的处理方式:

-- A functor in the second to last type argument
class Functor2 p where
  fmap2 :: (a -> a') -> p a b -> p a' b

instance Functor2 K where
  fmap2 = -- you fill in the blank

instance Functor2 p => Functor (Flip p b) where
  fmap = -- you fill in the blank