我正在第一章第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)
| ^^^^^^^^^^
有人可以解释该错误信息吗?我只是对错误消息感到困惑:
Actual type
推论为Flip K a a1
而不是Flip K a b
? K
的第三个参数?类型K
的定义只有一个a
但没有b
,b
仅出现在数据类声明的左侧(=
的左侧符号),而不是=
的类型类声明(newtype K a b = K a
符号的右侧)。Flip (K a)
更改为Flip x
?fmap f (Flip (K a)) = Flip (K (f a))
可以编译,有什么区别?答案 0 :(得分:2)
您犯了一个错误。 Flip
意味着您需要映射K
的 first 参数:
instance Functor (Flip K a) where
fmap f (Flip (K a)) = Flip (K (f a))
有充分的理由。其中之一是给类型 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