ron*_*ron 14 haskell typeclass
我明白了
instance (Foo a) => Bar a
instance (Xyy a) => Bar a
Run Code Online (Sandbox Code Playgroud)
GHC不考虑上下文,并且实例报告为重复.
什么是违反直觉的,(我猜)在选择实例后,它仍然需要检查上下文是否匹配,如果不匹配,则丢弃实例.那么为什么不反转顺序,并丢弃具有不匹配上下文的实例,并继续使用剩余的集合.
这会在某种程度上难以解决吗?我看到它如何能够在前期引起更多的约束解析工作,但就像有UndecidableInstances/ IncoherentInstances,不可能有ConsiderInstanceContexts"我知道我在做什么"的时候?
这打破了开放世界的假设。认为:
class B1 a
class B2 a
class T a
Run Code Online (Sandbox Code Playgroud)
如果我们允许约束消除实例的歧义,我们可以写
instance B1 a => T a
instance B2 a => T a
Run Code Online (Sandbox Code Playgroud)
并且可以写
instance B1 Int
Run Code Online (Sandbox Code Playgroud)
现在,如果我有
f :: T a => a
Run Code Online (Sandbox Code Playgroud)
然后f :: Int工作。但是,开放世界的假设说,一旦某些东西起作用,添加更多实例就无法破坏它。我们的新系统不遵守:
instance B2 Int
Run Code Online (Sandbox Code Playgroud)
会造成f :: Int歧义。T应该使用哪个实现?
另一种说法是你打破了连贯性。类型类的一致性意味着只有一种方法可以满足给定的约束。在普通的 Haskell 中,约束c只有一种实现。即使有重叠的实例,一致性通常也适用。这个想法是,instance T a与instance {-# OVERLAPPING #-} T Int不破的连贯性,因为GHC不能被欺骗,在一个地方,后者将用做前者的实例。(你可以用孤儿来欺骗它,但你不应该。)至少对我来说,连贯性似乎有些可取。从某种意义上说,类型类的使用是“隐藏的”,强制它明确无误是有意义的。你也可以用IncoherentInstancesand/or打破一致性unsafeCoerce,但是,你知道。
以范畴论的方式,范畴Constraint是细的:instance从一个Constraint到另一个至多有一个/箭头。我们首先构造两个箭头a : () => B1 Int和b : () => B2 Int,然后我们通过添加新箭头 来打破细度x_Int : B1 Int => T Int,y_Int : B2 Int => T Int使得x_Int . a和都是不相同的y_Int . b箭头() => T Int。钻石问题,有人吗?
这并不能回答您关于为什么会出现这种情况的问题。但请注意,您始终可以定义一个新类型包装器来消除两个实例之间的歧义:
newtype FooWrapper a = FooWrapper a
newtype XyyWrapper a = XyyWrapper a
instance (Foo a) => Bar (FooWrapper a)
instance (Xyy a) => Bar (XyyWrapper a)
Run Code Online (Sandbox Code Playgroud)
这还有一个额外的优点,即通过传递 FooWrapper 或 XyyWrapper,您可以明确控制要使用这两个实例中的哪一个(如果您的 a 恰好满足这两个实例)。