首页 文章

Haskell - 使我的数据成为Eq实例的“模糊类型变量”错误

提问于
浏览
1

我现在正在学习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'中定义......

我该如何解决?

......我搜索了现有的问题和答案 . 下面的一个似乎接近我的,但我认为我的代码已经解决了答案所暗示的要点 .

how to instance Eq without deriving

2 回答

  • 2

    问题是 MyMaybe 是一个参数化类型,但在表达式 MyNothing == MyNothing 中,编译器无法确定您是否意味着 MyMaybe IntMyMaybe StringMyMaybe (Int -> Bool) 或其他内容 .

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

    let b1 = MyNothing == (MyNothing :: MyMaybe Int)
    
  • 2

    问题是 MyNothing 的类型为 MyMaybe a ,对 a 可以没有限制 .

    当您编写 MyNothing == MyNothing 时, (==) :: (Eq b) => b -> b -> Bool 的类型将两个 MyNothing 限制为具有相同的类型(编译器最初以 MyNothing :: MyMaybe a0MyNothing :: MyMaybe a1 开头,但后来意识到 a0 == a1 ) .

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

    这是编译器放弃的点,说它无法解析约束 (Eq a0) ,因为类型变量 a0 是不明确的 .


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

    let b1 = MyNothing == (MyNothing :: MyMaybe Integer)   -- for example
    

    要么:

    let b1 = MyNothing == (MyNothing :: MyMaybe (Double, [String]))
    

    实际类型并不重要(只要它有一个 Eq 实例) .


    这种歧义不仅限于您的 MyMaybe 类型 . 您应该使用 MaybeNothing == Nothing )或 [][] == [] )获得相同的错误 . 在所有情况下都涉及多态常数( Nothing :: Maybe a[] :: [a] ) .


    你的例子确实在ghci中起作用 . 这是因为ghci使用extended defaulting rules并最终将 a 转换为 () ;即比较完成 MyNothing == (MyNothing :: MyMaybe ()) .

相关问题