请考虑以下代码:
{-# 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编译指示来编写上述实例。
现在,说我们想编写一个函数g:
g :: (Y a) => a -> a
g = f
没有IncoherentInstances或在其中一个实例中添加{-#INCOHERENT#-},这不会进行类型检查。但是,当我们添加此内容并询问ghci
ghci> :t f
f :: Y a => a -> a
突然改变了'f'的类型?
对于这个小例子,当我给f一个Int时,程序仍然会进行类型检查(表明上面只是一个“视觉错误”,但在更大的例子中,它不会进行类型检查,给我一个类似的错误:
Could not deduce (Y a) arising from a use of 'f
(...)
from the context: (..., X a, ...)
:type f
不报告已定义实体f
的类型。它报告表达式f
的类型。 GHC确实努力将多态性排除在表达式之外。特别是,在表达式中使用f
会触发X a
约束的简化(就像在约束中使用任何定义一样)。如果没有IncoherentInstances
,GHC将拒绝使用instance Y a => X a
,因为还有另一个实例与之重叠,因此GHC需要等待以查看应使用哪个实例。这样可以确保连贯性;曾经使用过的only X Int
实例是显式的“专用”实例。对于IncoherentInstances
,您说的是您并不关心连贯性,因此无论何时X a
出现在表达式中,GHC都会继续使用多态实例将Y a
简化为f
。您会看到奇怪的行为,有时使用X Int
可以使GHC正常运行,有时会抱怨没有Y Int
是GHC在何时简化约束方面做出了不同的内部决策的结果(您确实要求incoherence] >!)。用于查看definition类型的命令为:type +v
。 :type +v f
应该显示f
的类型,如“声明的”。希望您也可以看到IncoherentInstances
是一个坏主意。不要使用它。