{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
module OverlappingSpecificsError where
class EqM a b where
(===) :: a -> b -> Bool
instance {-# OVERLAPPABLE #-} Eq a => EqM a a where
a === b = a == b
instance {-# OVERLAPPABLE #-} EqM a b where
a === b = False
aretheyreallyeq :: (Eq a, Eq b) => Either a b -> Either a b -> Bool
aretheyreallyeq (Left a1) (Right b2) = a1 == b2
aretheyeq :: (Eq a, Eq b) => Either a b -> Either a b -> Bool
aretheyeq (Left a1) (Right b2) = a1 === b2
aretheyreallyeq
或aretheyeq
都没有编译,但是aretheyreallyeq
的错误对我来说很有意义,并且还告诉我aretheyeq
不应该给出错误:GHCi建议的一种情况可能适用于EqM
由于aretheyeq
上的相同错误,因此aretheyreallyeq
中的]应该是不可能的。发生了什么事?
重点是,GHCi坚持认为EqM
的两个实例都适用于aretheyeq
。但是a1
的类型为a
,b2
的类型为b
,因此,为了使第一个实例适用,必须将a
和b
的类型统一。
但是这不可能,因为它们在函数签名处被声明为类型变量(也就是说,使用第一个EqM
实例将导致该函数的类型为Either a a -> Either a a -> Bool
,并且错误发生在[C0 ]告诉我,GHCi不允许这样做(这也是我所期望的)。
我是否丢失了某些东西,或者这是一个如何检查具有多参数类型类的重叠实例的错误?
[我想也许与以下事实有关:aretheyreallyeq
和a
可以稍后在b
之外,再实例化到相等的点,然后是第一个实例将有效吗?但是aretheyeq
也是如此。唯一的区别是,如果他们不统一,我们可以选择aretheyreallyeq
,但不能选择aretheyeq
。无论如何,Haskell出于许多充分而显而易见的原因而没有动态调度,因此,不管以后aretheyreallyeq
和a
是否无法执行,提交将使always起作用的实例的恐惧是什么? ?也许有某种表达方式可以使调用函数时以某种方式选择实例?
值得注意的是,如果删除第二个实例,则该函数显然仍无法编译,并指出找不到任何实例b
。因此,如果我没有该实例,那么没有一个起作用,但是当那个实例起作用时,突然另一个实例也起作用,并且我有重叠吗?几英里外的我对我来说像臭虫。
通用变量上的实例匹配以这种方式工作,以防止出现某些可能造成混淆(和危险)的情况。
aretheyeq :: EqM a b => Either a b -> Either a b -> Bool
失败,因为作用域中有两个不同的类型变量。在aretheyreallyeq