data CouldBe a = Is a | Lost deriving (Show, Ord)
instance Eq (CouldBe m) where
Is x == Is y = x == y
Lost == Lost = True
_ == _ = False
给出错误:
No instance for (Eq m) arising from a use of ‘==’
所以:instance (Eq m) => Eq (CouldBe m) where
Is x == Is y = x == y
Lost == Lost = True
_ == _ = False
工作正常(至少我开始理解错误),但为什么我需要这个约束?
我正在努力学习,所以“为什么”对我来说非常重要。
最佳答案
您原来的定义是 CouldBe m
是 Eq
的一个实例适用于任何类型 m
,即使一个没有 Eq
实例。但如果这是真的,你必须找到某种方式来定义 Is x == Is y
不使用 x == y
(因为你没有要求 m
有一个 Eq
实例,x == y
不一定定义。)
作为一个具体的例子,它阻止你写类似的东西
Is (+3) == Is (* 5) -- (+3) == (*5) is undefined
添加约束确保您可以比较两个
CouldBe
仅当也可以比较包装类型时的值。没有添加约束的“有效”但微不足道的实例:
instance Eq (CouldBe m) where
Is x == Is y = True
Lost == Lost = True
_ == _ = False
两个
CouldBe m
只要它们共享相同的数据构造函数,值就相等,而不管包装的值如何。不尝试使用 x
或 y
完全,所以它们的类型可以不受约束。“有效”用引号引起来,因为这个定义可能违反了替代法,定义于 http://hackage.haskell.org/package/base-4.12.0.0/docs/Data-Eq.html .假设您有一个函数可以将
CouldBe
分开值(value):couldbe :: b -> (a -> b) -> CouldBe a -> b
couldBe x _ Lost = x
couldBe _ f (Is x) = f x
发生违规的原因是
Is 3 == Is 5
会是真的,但让 f = couldbe 0 id
.然后f (Is 3) == f (Is 5)
计算结果为 3 == 5
这是错误的。实际上是否违规取决于是否存在类似
couldbe
的函数。可以看到“内部”一个 CouldBe
值(value)。
关于具有类型构造函数的类型类定义的 Haskell 实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55048943/