GHC标记冗余的类型类约束为何删除后无法通过编译
GHC 冗余约束警告与编译报错矛盾问题说明
问题复现场景
在GHC 9.2.3版本中启用-Wredundant-constraints编译选项时,以下可正常编译的代码会触发冗余约束警告:
{-# LANGUAGE UndecidableInstances, FlexibleInstances #-} class Functor f => C f where c :: f Int instance (Functor f, Applicative f) => C f where c = pure 42
对应的警告输出如下:
test.hs:5:10: warning: [-Wredundant-constraints] • Redundant constraint: Functor f • In the instance declaration for ‘C f’ | 5 | instance (Functor f, Applicative f) => C f where c = pure 42 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
矛盾表现
如果按照警告提示删除被标记为冗余的Functor f约束,代码反而无法通过类型检查,对应报错信息如下:
-- 删除Functor f约束后的代码 instance Applicative f => C f where c = pure 42
test.hs:5:10: error: • Could not deduce (Functor f) arising from the superclasses of an instance declaration from the context: Applicative f bound by the instance declaration at test.hs:5:10-29 Possible fix: add (Functor f) to the context of the instance declaration • In the instance declaration for ‘C f’ | 5 | instance Applicative f => C f where c = pure 42 | ^^^^^^^^^^^^^^^^^^^^
从直觉上看Applicative f本身就隐含Functor f约束,Functor f理应属于冗余约束,但GHC同时给出「冗余警告」和「缺省报错」的矛盾表现,很容易让人困惑。
问题本质
这个现象是GHC 9.2版本中两套检查逻辑判定规则不一致导致的:
- 冗余约束检查逻辑:会递归追溯约束的超类关系,识别到
Applicative f的超类已经包含Functor f,因此判定实例上下文中手写的Functor f是多余的,触发警告。 - 实例超类满足性检查逻辑:在验证类
C要求的超类Functor f是否被实例上下文满足时,出于避免超类推导无限循环的考虑(当前实例开启了UndecidableInstances,且是匹配所有类型f的极泛化实例),不会递归追溯上下文里Applicative f隐含的超类,只会检查上下文里直接声明的约束,因此删除直接写的Functor f就会报错。
处理方案
这个警告属于GHC版本带来的误报:
- 从逻辑上
Functor f确实被Applicative f隐含,但在该版本GHC的实例检查规则下,这个约束是编译必需的,不能删除。 - 可以在该实例声明的局部范围内关闭
-Wredundant-constraints警告,消除误报提示。 - 该检查逻辑不一致的问题在后续GHC版本中已经被修复,升级GHC版本也可以解决这个矛盾。
内容的提问来源于stack exchange,提问作者yairchu
相关产品推荐
相关产品推荐

