各种“..Instances”编译指示如何协同工作,是否有解决我当前问题的方法?

How do the various "..Instances" pragma's work together, and is there a way around my current problem?

考虑以下代码:

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
class X a
class Y a
instance Y Bool
instance (Y a) => X a
instance {-# OVERLAPPING #-} X Int

f :: (X a) => a -> a
f x = x

编写上述实例需要这些 LANGUAGE pragma。

现在,假设我们要编写一个函数 g:

g :: (Y a) => a -> a
g = f

没有 IncoherentInstances 或向其中一个实例添加 {-# INCOHERENT #-},这不会进行类型检查。 但是当我们添加这个,并询问 ghci

ghci> :t f
f :: Y a => a -> a

'f' 的类型突然改变了?

对于这个小例子,当我给 f 一个 Int 时,程序仍然会进行类型检查(表明上面只是一个 'visual bug',但在一个更大的例子中,它不会进行类型检查,给我一个错误:

Could not deduce (Y a) arising from a use of 'f
(...)
from the context: (..., X a, ...)

当我们说

时也会发生这种情况
h = f

并尝试用 Int

调用 h

:type f 不报告已定义实体的类型 f。它报告表达式 f 的类型。 GHC 非常努力地从表达式中去除多态性。特别是,在表达式中使用 f 会触发 X a 约束的简化(就像使用任何带约束的定义一样)。如果没有 IncoherentInstances,GHC 会避免使用 instance Y a => X a,因为还有另一个实例与它重叠,因此 GHC 需要等待,看看它应该使用哪个。这确保了连贯性; only X Int 曾经使用过的实例是明确的 "specialized" 实例。使用 IncoherentInstances,你说你不关心连贯性,所以只要 f 出现在表达式中,GHC 就会继续使用多态实例将 X a 简化为 Y a。您看到的奇怪行为有时 GHC 可以使用 X Int 有时抱怨没有 Y Int 是 GHC 对何时要简化约束做出不同的内部决定的结果(您确实要求不连贯!)。查看定义类型的命令是:type +v:type +v f 应该显示 f "as declared" 的类型。希望您也能看到 IncoherentInstances 是个坏主意。不要使用它。