对方法的约束取决于范围内的实例?

Constraint on method depends on instances in scope?

考虑这段代码:

{-# language FlexibleInstances, UndecidableInstances #-}

module Y where

class C m where

    x :: m

instance {-# overlappable #-} Monoid m => C m where

    x = mempty

instance C Int where

    x = 53

x 的类型是什么?

λ :type x
x :: C m => m

到目前为止 - 很好。现在删除 Int 实例。 x 的类型是什么?

λ :type x
x :: Monoid m => m

惊喜!

为什么会这样?

此行为在以下博客中进行了解释 post:

简而言之:GHC 足够聪明,可以看到您只有一个 C 类型类的实例,并确定它是唯一可能的实例,所以每次它看到 C m 约束时,它将其替换为 Monoid m 因为它们是等价的。

N.B. 正如@chi 在评论中进一步解释的那样:

当 GHC 发现约束 C t 时,它会尝试解决它。如果找到匹配的 instance (...) => C t where ...,约束将替换为上下文 (...)。尽可能多地重复此操作。最终约束出现在类型中(或触发 "unsolved" 类型错误)。这个过程是合理的,因为最多只能有一个匹配的实例。重叠的实例改变了这一点,并在多个实例(在范围内!)大致匹配时防止这种上下文减少。这是一个脆弱的扩展,使用时要小心。