具有类型构造函数的Typeclass定义的Haskell实例

时间:2019-03-07 16:47:21

标签: haskell constraints typeclass

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 

工作正常(至少我开始理解错误),但是为什么需要该约束? 我正在尝试学习,所以“为什么”对我来说非常重要。

1 个答案:

答案 0 :(得分:7)

您最初的定义是CouldBe m是{em> any 类型Eq的{​​{1}}的实例,甚至没有{{1} }实例。但是,如果是这样,则必须找到一种无需使用m即可定义Eq的方法(因为您不需要Is x == Is y拥有一个x == y实例,{{1 }}不一定要定义。)

作为一个具体示例,它阻止您编写类似的内容

m

添加约束可确保仅在还可以比较包装类型的情况下才可以比较两个Eq值。


一个“有效”但微不足道的实例,没有添加约束:

x == y

两个Is (+3) == Is (* 5) -- (+3) == (*5) is undefined 值相等,只要它们共享相同的数据构造函数,而与包装值无关。完全没有尝试使用CouldBeinstance Eq (CouldBe m) where Is x == Is y = True Lost == Lost = True _ == _ = False ,因此它们的类型可以不受限制。

用引号引起来是有效的,因为此定义可能违反在http://hackage.haskell.org/package/base-4.12.0.0/docs/Data-Eq.html上定义的替代法则。假设您有一个函数可以分解一个CouldBe m值:

x

发生冲突是因为y为真,但让CouldBe为准。然后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)值的内部“看到”。