这真的很简单。让我们询问 GHCi 的类型是什么isList2
is:
∀x. x ⊢ :t isList2
isList2 :: a -> Bool
这不符合[a]
实例(尽管它可以通过统一),但它确实匹配a
立即实例。因此,GHC 选择a
实例,所以isList2
回报False
.
这种行为正是IncoherentInstances
方法。事实上,这是一个相当不错的演示。
有趣的是,如果你只是禁用IncoherentInstances
,我们得到了完全相反的效果,GHCi 现在这样说:
∀x. x ⊢ :t isList2
isList2 :: [Integer] -> Bool
发生这种情况是因为isList2
是一个顶级绑定,不是使用函数语法定义的,因此受到可怕的单态限制的约束。因此它专门针对实际使用的实例。
Adding NoMonomorphismRestriction
以及禁用IncoherentInstances
,我们得到这个:
∀x. x ⊢ :t isList2
isList2 :: IsList a => a -> Bool
∀x. x ⊢ isList2 'a'
False
∀x. x ⊢ isList2 "a"
True
∀x. x ⊢ isList2 undefined
<interactive>:19:1:
Overlapping instances for IsList a0 arising from a use of `isList2'
这是预期的重叠行为,如果选择不明确,则根据使用和投诉选择实例。
关于对问题的编辑,我认为如果没有类型注释就不可能获得所需的结果。
第一个选项是给isList2
类型签名,它可以防止IncoherentInstances
过早选择实例。
isList2 :: (IsList a) => a -> Bool
isList2 = isList
您可能需要在其他地方做同样的事情isList
被提及(甚至间接)但没有应用于论证。
第二个选项是消除数字文字的歧义并禁用IncoherentInstances
.
main =
print (isList (42 :: Integer)) >>
print (isList2 (42 :: Integer)) >>
print (isList [42]) >>
print (isList2 [42])
在这种情况下,有足够的信息来选择最具体的实例,因此OverlappingInstances
做它的事。