各种"..Instances"编译指示如何协同工作,有没有办法解决我当前的问题?



考虑以下代码:

{-# 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

如果没有非相干实例或向其中一个实例添加{-#INC相干#-},则不会进行类型检查。但当我们添加这个,并询问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, ...)

当我们说时也会发生这种情况

h = f

并尝试用Int 调用h

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

最新更新