Haskell/GHC:报告了重叠实例,而上下文只允许一个实例

Haskell/GHC: overlapping instances reported while context only allows a single one

尊敬的 Haskell/GHC 专家,

我真的不明白为什么 GHC 报告重叠实例,而根据提供的上下文只有一个实际有效。例如,让我们考虑以下代码:

{-# LANGUAGE FlexibleInstances #-}

class C a where
    foo :: a -> String
    foo x = "OK"

instance C Bool
instance (C a) => C [a]
instance (C a) => C [(Char, a)]

main = print $ foo [('a', True)]

编译得到:

Test.hs:13:16: error:
    * Overlapping instances for C [(Char, Bool)]
        arising from a use of `foo'
      Matching instances:
        instance C a => C [a] -- Defined at Test.hs:9:10
        instance C a => C [(Char, a)] -- Defined at Test.hs:11:10
    * In the second argument of `($)', namely `foo [('a', True)]'
      In the expression: print $ foo [('a', True)]
      In an equation for `main': main = print $ foo [('a', True)]

要点是 ('a', True) 的类型 (Char, Bool) 不是 C 的实例。因此,instance C a => C [a]不适用于值[('a', True)]

那么,为什么GHC会考虑呢?

问题实际上是关于理解 GHC 的行为,而不是关于如何避免该问题(例如使用 OverlappingInstances)。是因为 "resolving" 函数调用时没有使用上下文吗?如果是,为什么?

提前致谢!

我的理解(可能非常错误):

首先,来自documentation

When matching, GHC takes no account of the context of the instance declaration (context1 etc). GHC's default behaviour is that exactly one instance must match the constraint it is trying to resolve. It is fine for there to be a potential of overlap (by including both declarations (A) and (B), say); an error is only reported if a particular constraint matches more than one.

The -XOverlappingInstances flag instructs GHC to allow more than one instance to match, provided there is a most specific one.

在您的例子中,传递给 foo 的类型是 [(Char,Bool)]。这满足通用的 [a] 和更专业的 [(Char,a)]。在没有OverlappingInstances标志的情况下,最具体的匹配场景不适用,报错。

现在,如果您像这样稍微调整一下代码:

instance C Bool
instance (C a) => C [a]
instance (C a) => C (Char, a)

那么就不会有重叠,因为元组不是列表。