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

Haskell instance of typeclass definition with type constructor

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 

工作正常(至少我开始理解错误),但为什么我需要那个约束? 我正在努力学习,所以 'why' 对我来说非常重要。

您最初的定义是 CouldBe many 类型 mEq 实例,即使没有一个 Eq 实例。但如果这是真的,你必须找到一些不使用 x == y 来定义 Is x == Is y 的方法(因为你不需要 m 来拥有一个 Eq 实例,x == y 不一定定义。)

举个具体的例子,它会阻止你写类似

的东西
Is (+3) == Is (* 5)  -- (+3) == (*5) is undefined

添加约束确保您可以比较两个 CouldBe 值,前提是包装类型也可以进行比较。


A "valid",但很简单,没有添加约束的实例:

instance Eq (CouldBe m) where
  Is x == Is y = True
  Lost == Lost = True
  _ == _ = False

两个 CouldBe m 值只要共享相同的数据构造函数就相等,无论包装值如何。根本没有尝试使用 xy,因此它们的类型可以不受约束。

"Valid" 在引号中,因为此定义可能违反了 http://hackage.haskell.org/package/base-4.12.0.0/docs/Data-Eq.html 中定义的替代法则。假设您有一个函数可以拆分 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) 的计算结果为 3 == 5,这是错误的。

是否实际上违规取决于是否存在像couldbe这样的函数可以看到"inside"一个CouldBe值.