Haskell - 使我的数据成为Eq

时间:2017-08-27 10:04:59

标签: haskell

我现在正在学习Haskell并尝试将我的数据(类似于Maybe)作为Eq的实例,如下所示。

module Main where

data MyMaybe a = MyNothing | MyJust a

instance (Eq a) => Eq (MyMaybe a) where
  MyNothing == MyNothing = True
  MyJust x == MyJust y = x == y
  _ == _ = False

main :: IO ()
main = do
  let b0 = MyJust 42 == MyJust 42 -- OK
  print b0                        -- True
  let b1 = MyNothing == MyNothing -- Build error!
  print b1

但是编译器在行let b1 = MyNothing == MyNothing中返回错误,如下所示。

  

?暧昧类型变量“A0”从使用所产生的“==”   防止约束“(等式A0)”被解决。   可能的解决办法:使用类型注释,以指定“A0”应该是。   这些潜在的情况下存在:   实例等式订购 - 在“GHC.Classes”定义

     

...

我该如何解决?

...我搜索了现有的问题和答案。下面的内容似乎与我的相近,但我认为我的代码已经解决了答案中提出的要点。

how to instance Eq without deriving

2 个答案:

答案 0 :(得分:2)

问题是MyMaybe是参数化类型,但在表达式MyNothing == MyNothing中,编译器无法确定您是否需要MyMaybe IntMyMaybe String,{ {1}},或其他。

您可以使用类似的类型注释来帮助它:

MyMaybe (Int -> Bool)

答案 1 :(得分:2)

问题在于MyNothing的{​​{1}}类型对MyMaybe a的限制没有限制。

当您编写a时,MyNothing == MyNothing的类型将两个(==) :: (Eq b) => b -> b -> Bool限制为具有相同的类型(编译器最初以MyNothing和{{1开头但是,然后意识到MyNothing :: MyMaybe a0)。

但要解决MyNothing :: MyMaybe a1本身,编译器需要找到正确的a0 == a1实例(因为那里定义了==)。我们的类型是Eq,这很好:我们在那里有一个==实例。但它还需要一个MyMaybe a实例,由于我们不知道Eq (MyMaybe a)是什么,因此无法解决。 (在Eq a情况下a实际上没有使用并不重要;类型检查不会注意运行时值。)

这是编译器放弃的地方,说它无法解析约束(Eq a),因为类型变量MyNothing == MyNothing不明确。

解决这个问题很简单。只需给编译器一个提示应该使用哪种类型:

(Eq a0)

或者:

a0

实际类型并不重要(只要它有一个let b1 = MyNothing == (MyNothing :: MyMaybe Integer) -- for example 实例)。

这种歧义并不仅限于您的let b1 = MyNothing == (MyNothing :: MyMaybe (Double, [String])) 类型。您应该使用EqMyMaybe)或MaybeNothing == Nothing)获得相同的错误。在所有情况下都涉及多态常量([][] == [])。

您的示例实际上在ghci中有效。这是因为ghci使用extended defaulting rules并最终将Nothing :: Maybe a转换为[] :: [a];即比较以a完成。