{-# 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
编译,但是 for 的错误对aretheyreallyeq
我来说是有意义的,并且还告诉我不aretheyeq
应该给出错误:GHCi 建议的可能 for EqM
in的实例之一aretheyeq
应该是不可能的,因为aretheyreallyeq
. 这是怎么回事?
关键是,GHCi 坚持认为 的两个实例EqM
都适用于aretheyeq
. But a1
is of typea
和b2
is of type b
,所以为了使第一个实例适用,它必须具有类型a
和b
统一。
但这应该是不可能的,因为它们在函数签名处被声明为类型变量(也就是说,使用第一个EqM
实例会导致函数为 type Either a a -> Either a a -> Bool
,并且aretheyreallyeq
告诉我 GHCi 不允许这样做(无论如何都是我所期望的)。
我是否遗漏了什么,或者这是如何检查具有多参数类型类的重叠实例的错误?
我在想这可能与这样一个事实有关,a
并且b
以后可以进一步实例化到它们相等的点, outside aretheyeq
,然后第一个实例是有效的?但对于aretheyreallyeq
. 唯一的区别是,如果他们不统一,我们可以选择aretheyeq
,但我们没有aretheyreallyeq
。在任何情况下,Haskell 没有动态调度有很多好的和明显的原因,所以有什么害怕提交实例总是有效的,无论以后a
是否b
统一也许有某种方法可以在以某种方式调用函数时选择实例?
值得注意的是,如果我删除第二个实例,那么该函数显然仍然无法编译,说明找不到实例EqM a b
。因此,如果我没有那个实例,那么没有一个有效,但是当那个有效时,突然另一个也有效并且我有重叠?几英里外的我闻起来像虫子。