Haskell中类型类约束使用TypeError时如何避免编写undefined
问题说明
当前用于实现缺失实例自定义报错的类型类代码如下:
instance {-# OVERLAPPABLE #-} (TypeError ( 'Text "Some error")) => SomeClass x where someMethod = undefined
这个兜底实例放在所有合法实例之后,预期效果是目标类型匹配不到对应合法实例时,编译器直接抛出自定义类型错误。现有写法的问题是必须给所有类方法填充undefined作为占位实现,属于冗余的hack写法。
解决方案
完全可以去掉undefined占位,直接用GHC.TypeError自带的多态值typeError作为方法实现,不需要额外取巧。
优化后代码:
import GHC.TypeError (TypeError(..), ErrorMessage(..)) instance {-# OVERLAPPABLE #-} TypeError ('Text "Some error") => SomeClass x where someMethod = typeError
写法细节
typeError的自带类型签名为TypeError msg => a,是多态值,可以匹配任意类方法的类型,完全不需要用undefined做无意义占位。- 语义比
undefined清晰得多:typeError直接对应编译期报错的逻辑,不会像undefined一样误导阅读者认为这里存在运行时崩溃的风险。 - 没有额外运行时开销或风险:只要这个兜底实例被类型检查器选中,实例上下文的
TypeError约束会直接触发编译期报错,根本不会生成后续可执行代码,方法体内容永远不会被实际执行。 - 后续给类型类新增方法时,只需要给新方法补
= typeError的实现即可,不需要写其他冗余逻辑。
其他可选方案
如果你的需求是「只有实际调用类方法时才触发类型错误,而非只要出现SomeClass x约束就报错」,可以把TypeError约束从实例头移动到对应方法的类型签名上,按需选择即可。
注意必须给这个兜底实例加{-# OVERLAPPABLE #-} pragma,保证其他更具体的合法实例能正常覆盖兜底逻辑,不会被错误拦截。
内容的提问来源于stack exchange,提问作者Sridhar Ratnakumar
相关产品推荐
相关产品推荐

