【发布时间】:2020-02-13 01:58:47
【问题描述】:
{-# 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 建议的实例之一对于 @ 是可能的由于aretheyreallyeq 上的相同错误,aretheyeq 中的 987654326@ 应该是不可能的。怎么回事?
关键是,GHCi 坚持EqM 的两个实例都适用于aretheyeq。但是a1 是a 类型,而b2 是b 类型,所以为了使第一个实例适用,它必须具有a 和b 类型统一。
但这应该是不可能的,因为它们在函数签名处被声明为类型变量(也就是说,使用第一个 EqM 实例会导致函数的类型为 Either a a -> Either a a -> Bool,并且 @ 中的错误987654339@ 告诉我 GHCi 不允许这样做(无论如何,这是我所期望的)。
我是否遗漏了什么,或者这是如何检查具有多参数类型类的重叠实例的错误?
我在想这可能与a 和b 可以在以后进一步实例化到它们相等的点有关,在aretheyeq 之外,然后第一个实例会 有效吗?但aretheyreallyeq 也是如此。唯一的区别是,如果他们不统一,我们可以选择aretheyeq,但我们没有aretheyreallyeq。在任何情况下,Haskell 没有动态调度有很多好的和明显的原因,所以在提交实例时担心会总是工作,无论以后是否a 和@987654347 @是统一的吗?也许有一些方法可以在调用函数时以某种方式选择实例?
值得注意的是,如果我删除第二个实例,那么该函数显然仍然无法编译,说明找不到实例EqM a b。所以如果我没有那个实例,那么没有一个有效,但是当那个有效时,突然另一个也有效,我有重叠?几英里外我闻起来像虫子。
【问题讨论】:
-
您可能希望在运行时而不是编译时比较
a和b类型是否相等。如果是这样,您可以使用Typeable a, Typeable b作为附加约束。请注意,如果这样做,则必须在每次调用时满足约束。
标签: haskell typeclass overlapping-instances multiparameter