GHC 9.2中Ambiguous record fields警告的最优解决方法咨询
GHC 9.2+ 重复记录字段歧义问题解答
GHC 9.2对DuplicateRecordFields扩展的行为做了变更:此前通过foo (a :: Aaa)这种给参数加类型注解来消除字段歧义的写法,会触发ambiguous-fields警告,且该写法在未来版本会被移除支持。
现有方案分析
- func1:
foo (a :: Aaa)触发警告的原因是,GHC不再认可通过参数类型注解反向推断字段所属类型的逻辑,编译器认为这种写法仍存在歧义,因此标记为过时。 - func3:
foo a'等价于直接写foo a,无法消除歧义。因为DuplicateRecordFields允许不同类型拥有同名字段,字段选择器本身是多态的,仅靠参数的类型无法让编译器明确选择对应类型的字段。 - func2:通过
case模式匹配结合RecordWildCards,将Aaa类型的foo字段绑定到当前作用域,此时的foo是明确的局部变量,完全消除了歧义,这是一个合规且无警告的有效写法。
其他最优替代方案
除了func2,还有更简洁的方案可选:
- 使用TypeApplications扩展显式指定类型
开启TypeApplications扩展后,可以直接给字段选择器指定类型参数,明确要使用哪个类型的字段:
{-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE TypeApplications #-} func4 :: Int func4 = foo @Aaa a
这种写法无需额外的模式匹配,代码更简洁,同样不会触发警告。
- 显式模式匹配(不依赖RecordWildCards)
如果不想使用RecordWildCards扩展,可以直接在模式匹配中绑定字段值:
{-# LANGUAGE DuplicateRecordFields #-} func5 :: Int func5 = case a of Aaa { foo = fooVal } -> fooVal
逻辑清晰,同样能消除歧义。
总结
func2是可行的解决方案,但并非唯一的最优选择。如果项目允许启用TypeApplications,foo @Aaa a的写法更简洁高效;若偏好无额外扩展的写法,显式模式匹配也是不错的选择,可根据项目的扩展配置和代码风格灵活选用。
内容的提问来源于stack exchange,提问作者Tsvetan Ovedenski
相关产品推荐
相关产品推荐

