GHC重叠实例下bar类型可推导但foo'失败的原因及解决方法
问题分析与解决
示例代码:
class Foo a where foo :: a -> a instance Foo a where foo = id instance {-# OVERLAPPING #-} Foo Int where foo x = x + 1 bar () = foo foo' = foo
GHC能正确推导bar的类型为bar :: Foo a => () -> a -> a,但推导foo'时会抛出错误:
Overlapping instances for Foo a0 arising from a use of ‘foo’
原因解析
核心差异来自单态限制(Monomorphism Restriction):
- 对于
bar () = foo这种带显式参数的函数绑定,GHC默认不会触发单态限制,会推导完全多态的类型。此时foo作为返回值,其类型a->a的约束Foo a被提升为bar的顶层约束,不需要确定具体的a类型,也就不会触发实例选择,因此不会报错。 - 对于
foo' = foo这种无参数的绑定,GHC默认会触发单态限制,尝试将其推导为单态类型。这时候GHC需要为foo的类型变量a确定一个具体实例,但存在重叠的Foo a(通用实例)和Foo Int(重叠实例),GHC无法自动选择,因此抛出重叠实例的错误。
解决方法
关闭单态限制即可让GHC自动推导foo'的多态类型:
在编译时添加-XNoMonomorphismRestriction选项,或者在代码开头添加语言扩展声明:
{-# LANGUAGE NoMonomorphismRestriction #-}
开启该扩展后,GHC会为foo'推导预期的多态类型Foo a => a -> a,不再尝试强制实例化单态类型,也就不会触发重叠实例的冲突。
内容的提问来源于stack exchange,提问作者141592653
相关产品推荐
相关产品推荐

