Haskell重叠/不连贯实例 [英] Haskell Overlapping/Incoherent Instances
问题描述
我知道这是代码有点傻,但有人可以解释为什么 isList [42]
返回 True
而 isList2 [42]
打印 False
,以及如何防止这种情况?我想更好地理解一些比较模糊的GHC类型的扩展,我认为这将是一个有趣的例子。
{ - #LANGUAGE FlexibleInstances# - }
{ - #LANGUAGE OverlappingInstances# - }
{ - #LANGUAGE IncoherentInstances# - }
$ b $ class IsList a where
isList :: a - > Bool
实例IsList a其中
isList x = False
实例IsList [a]其中
isList x = True
isList2 = isList
main =
print(isList 42)>>
print(isList2 42)>>
print(isList [42])>>
print(isList2 [42])
这真的很简单。让我们问GHCi isList2
的类型是:
∀x。 x⊢:t isList2
isList2 :: a - > Bool
这不符合 这种行为恰恰是 如果您只是禁用 发生这种情况是因为 添加 这是预期的重叠行为,如果选择不明确,则根据使用情况和投诉选择实例。 关于对问题的编辑,我不相信如果没有类型注释,所需的结果是不可能的。 第一个选项是给 您可能需要在其他地方执行相同操作 第二个选项是消除数字文字的歧义,禁用 在这种情况下,有足够的信息可以选择最具体的实例,所以 I know this is code is a bit silly, but can someone explain why this
It's really quite simple. Let's ask GHCi what the type of This doesn't match the This behavior is precisely what Hilariously, if you simply disable This happens because Adding Which is the expected overlapping behavior, with the instance chosen based on use and complaints if the choice is ambiguous. Regarding the edit to the question, I don't believe the desired result is possible without type annotations. The first option is to give You'll probably need to do the same anywhere else The second option is to disambiguate the numeric literals and disable In this case, there's enough information to pick a most-specific instance, so 这篇关于Haskell重叠/不连贯实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋! [a] $ c $ (即使它可以通过统一),但它立即匹配
a
实例。因此,GHC选择 a
实例,所以 isList2
返回 False
。
IncoherentInstances
的意思。实际上,这是一个相当不错的演示。
IncoherentInstances
,我们得到完全相反的效果,GHCi现在这样说:
∀x。 x⊢:t isList2
isList2 :: [Integer] - > Bool
isList2
是顶部没有使用函数语法定义的级别绑定,因此受到可怕的单态限制。因此它专用于实际使用的实例。
NoMonomorphismRestriction
以及禁用 IncoherentInstances
,我们得到它:
∀x。 x⊢:t isList2
isList2 :: IsList a => a - > Bool
∀x。 x⊢isList2'a'
False
∀x。 x⊢isList2a
True
∀x。 x⊢isList2 undefined
< interactive>:19:1:
使用'isList2'产生的IsList a0的重叠实例
> isList2
一个类型签名,它可以防止 IncoherentInstances
过早选择一个实例。 p>
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
完成它的工作。isList [42]
returns True
whereas isList2 [42]
prints False
, and how to prevent this? I'd like to get better understanding of some of the more obscure GHC type extensions, and I thought this would be an interesting example to figure out.{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverlappingInstances #-}
{-# LANGUAGE IncoherentInstances #-}
class IsList a where
isList :: a -> Bool
instance IsList a where
isList x = False
instance IsList [a] where
isList x = True
isList2 = isList
main =
print (isList 42) >>
print (isList2 42) >>
print (isList [42]) >>
print (isList2 [42])
isList2
is:∀x. x ⊢ :t isList2
isList2 :: a -> Bool
[a]
instance (even though it could, via unification), but it does match the a
instance immediately. Therefore, GHC selects the a
instance, so isList2
returns False
.IncoherentInstances
means. Actually, this is a rather nice demonstration of it.
IncoherentInstances
, we get exactly the opposite effect, and GHCi now says this:∀x. x ⊢ :t isList2
isList2 :: [Integer] -> Bool
isList2
is a top-level binding not defined using function syntax, and thus subject to the Dreaded Monomorphism Restriction. So it gets specialized to the instance it's actually used with.NoMonomorphismRestriction
as well as disabling IncoherentInstances
, we get this instead:∀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
a type signature, which prevents IncoherentInstances
from selecting an instance too early.isList2 :: (IsList a) => a -> Bool
isList2 = isList
isList
is mentioned (even indirectly) without being applied to an argument.IncoherentInstances
. main =
print (isList (42 :: Integer)) >>
print (isList2 (42 :: Integer)) >>
print (isList [42]) >>
print (isList2 [42])
OverlappingInstances
does its thing.