这种类型类约束是必要的还是多余的?

yai*_*chu 10 haskell typeclass ghc

以下代码成功编译,但在使用 GHC 9.2.3 时收到警告-Wredundant-constraints

\n
{-# LANGUAGE UndecidableInstances, FlexibleInstances #-}\n\nclass Functor f => C f where c :: f Int\n\ninstance (Functor f, Applicative f) => C f where c = pure 42\n
Run Code Online (Sandbox Code Playgroud)\n

由此产生的警告:

\n
test.hs:5:10: warning: [-Wredundant-constraints]\n    \xe2\x80\xa2 Redundant constraint: Functor f\n    \xe2\x80\xa2 In the instance declaration for \xe2\x80\x98C f\xe2\x80\x99\n  |\n5 | instance (Functor f, Applicative f) => C f where c = pure 42\n  |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n
Run Code Online (Sandbox Code Playgroud)\n

但是,如果我删除此约束,代码将不再进行类型检查:

\n
test.hs:5:10: error:\n    \xe2\x80\xa2 Could not deduce (Functor f)\n        arising from the superclasses of an instance declaration\n      from the context: Applicative f\n        bound by the instance declaration at test.hs:5:10-29\n      Possible fix:\n        add (Functor f) to the context of the instance declaration\n    \xe2\x80\xa2 In the instance declaration for \xe2\x80\x98C f\xe2\x80\x99\n  |\n5 | instance Applicative f => C f where c = pure 42\n  |          ^^^^^^^^^^^^^^^^^^^^\n
Run Code Online (Sandbox Code Playgroud)\n

这让我很困惑。

\n

这个限制真的是多余的,还是实际上是必要的?

\n

直觉上我会说它是多余的,因为它已经暗示了Applicative f!但 GHC 不敢苟同,所以我不确定。

\n

K. *_*uhr 9

因此,Functor f看起来多余,但需要避免递归超类导致字典包含实际上位于底部的超类字段的问题(即,当隐式访问超类时,运行时出现无限循环)。

编译器源代码中标题为“递归超类”的compiler/GHC/Tc/TyCl/Instance.hs部分有一个解释。结果是,在解析 的超类时,不允许使用 GHC来解析,因为它不是比 更小的字典(见下文)。通过要求仅通过一系列更小的字典来解析超类,GHC 可以确保超类解析终止。Functor finstance C fApplicative fFunctor fApplicative fC f

相反,Functor f对于这个类似的示例,实例定义中不需要:

class Functor f => C f x
instance (Applicative f) => C f Int
Run Code Online (Sandbox Code Playgroud)

因为Applicative f是一个比 更小的字典C f Int,所以 GHC 被允许使用它。

这里的“较小词典”是在特定的技术意义上使用的。字典的大小是其类型中构造函数和变量的数量。因此,Applicative f的尺寸为 2,而 的C f Int尺寸为 3。

这意味着这实际上Functor f 并不是多余的,因此警告是错误的。发出警告看起来像是 GHC 错误。