对方法的约束取决于范围内的实例?
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" 类型错误)。这个过程是合理的,因为最多只能有一个匹配的实例。重叠的实例改变了这一点,并在多个实例(在范围内!)大致匹配时防止这种上下文减少。这是一个脆弱的扩展,使用时要小心。
考虑这段代码:
{-# 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" 类型错误)。这个过程是合理的,因为最多只能有一个匹配的实例。重叠的实例改变了这一点,并在多个实例(在范围内!)大致匹配时防止这种上下文减少。这是一个脆弱的扩展,使用时要小心。