我现在正在学习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'可以防止约束'(Eq a0)'被解决 . 可能的修复:使用类型注释来指定'a0'应该是什么 . 这些潜在的实例存在:实例Eq Ordering - 在'GHC.Classes'中定义......
我该如何解决?
......我搜索了现有的问题和答案 . 下面的一个似乎接近我的,但我认为我的代码已经解决了答案所暗示的要点 .
2 回答
问题是
MyMaybe
是一个参数化类型,但在表达式MyNothing == MyNothing
中,编译器无法确定您是否意味着MyMaybe Int
,MyMaybe String
,MyMaybe (Int -> Bool)
或其他内容 .您可以使用类似这样的类型注释来帮助它:
问题是
MyNothing
的类型为MyMaybe a
,对a
可以没有限制 .当您编写
MyNothing == MyNothing
时,(==) :: (Eq b) => b -> b -> Bool
的类型将两个MyNothing
限制为具有相同的类型(编译器最初以MyNothing :: MyMaybe a0
和MyNothing :: MyMaybe a1
开头,但后来意识到a0 == a1
) .但要解决
==
本身,编译器需要找到正确的Eq
实例(因为这是定义==
的地方) . 我们的类型是MyMaybe a
,这很好:我们在那里有一个Eq (MyMaybe a)
实例 . 但它还需要一个Eq a
实例,由于我们不知道a
是什么,因此无法解析 . (在MyNothing == MyNothing
情况下(Eq a)
实际上没有使用并不重要;类型检查不关注运行时值 . )这是编译器放弃的点,说它无法解析约束
(Eq a0)
,因为类型变量a0
是不明确的 .解决这个问题很容易 . 只需给编译器一个提示应该使用哪种类型:
要么:
实际类型并不重要(只要它有一个
Eq
实例) .这种歧义不仅限于您的
MyMaybe
类型 . 您应该使用Maybe
(Nothing == Nothing
)或[]
([] == []
)获得相同的错误 . 在所有情况下都涉及多态常数(Nothing :: Maybe a
,[] :: [a]
) .你的例子确实在ghci中起作用 . 这是因为ghci使用extended defaulting rules并最终将
a
转换为()
;即比较完成MyNothing == (MyNothing :: MyMaybe ())
.