Haskell定义String与列表类型类实例时为何出现[Char]重叠报错
报错原因
Haskell的类型类实例匹配规则是:先匹配实例头,再校验实例约束,约束不会影响实例的匹配判定,只要实例头匹配成功,就会进入候选实例列表,约束是实例选中之后才会验证的条件。
你调用getHello "hello"时,传入参数的类型是String(等价于[Char]),需要匹配Example [Char]的实例,此时会先扫描所有已定义的实例头:
- 第一个实例头是
Example String,因为String是[Char]的类型别名,完全匹配Example [Char],进入候选 - 第二个实例头是
Example [a],将类型变量a替换为Char后,实例头也匹配Example [Char],同样进入候选
此时两个候选实例优先级一致,直接触发重叠实例报错,根本不会走到校验第二个实例的Example a约束是否满足的步骤,所以即使你没有定义Example Char的实例,也会先报重叠错误。
解决方法
可以通过GHC的实例重叠标注扩展解决,给更具体的实例添加更高优先级的标注:
{-# LANGUAGE TypeSynonymInstances #-} {-# LANGUAGE FlexibleInstances #-} main = do print "hello" print $ getHello $ "hello" class Example a where getHello :: a -> String -- 给更具体的String实例标注为更高优先级的可重叠实例 instance {-# OVERLAPS #-} Example String where getHello _ = "blablabla" -- 也可选择给更通用的列表实例标注为可被覆盖 -- instance {-# OVERLAPPABLE #-} Example a => Example [a] where instance Example a => Example [a] where getHello v = undefined
内容的提问来源于stack exchange,提问作者Chris Stryczynski
相关产品推荐
相关产品推荐

