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

Ign*_*rov 6 haskell type-inference typeclass

考虑以下代码:

{-# 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
Run Code Online (Sandbox Code Playgroud)

什么是x

? :type x
x :: C m => m
Run Code Online (Sandbox Code Playgroud)

到目前为止,一切都很好。现在删除Int实例。什么是x

? :type x
x :: Monoid m => m
Run Code Online (Sandbox Code Playgroud)

惊喜!

 

为什么会这样呢?

She*_*rsh 7

以下博客文章中对此行为进行了解释:

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

 

NB   As @chi在评论中进一步解释:

当GHC找到约束时C t,它将尝试解决它。如果找到匹配项instance (...) => C t where ...,则将约束替换为上下文(...)。尽可能重复此过程。最终约束出现在类型中(或触发“未解决的”类型错误)。该过程是合理的,因为最多只能有一个匹配的实例。重叠的实例会更改此设置,并在多个实例(在范围内)大致匹配时防止这种上下文减少。这是一个易碎的扩展,需要谨慎使用。

  • @IgnatInsarov当GHC找到约束`C t'时,它将尝试解决它。如果找到匹配的`instance(...)=> C t where ...`,则将约束替换为上下文`(...)`。尽可能重复此过程。最终约束出现在类型中(或触发“未解决的”类型错误)。该过程是合理的,因为最多只能有一个匹配的实例。重叠的实例会更改此设置,并在多个实例(在范围内)大致匹配时防止这种上下文减少。这是一个_fragile_扩展名,请谨慎使用。 (2认同)
  • @chi我可以自由地整合您的评论。我觉得我可以这样接受答案。 (2认同)