为记录类型定义Type class实例报instance head invalid错误如何解决
错误成因
这是类Haskell强类型函数式语言的默认类型类规则限制:
- 默认情况下,类型类实例头部的类型必须为「类型构造器 + 若干类型参数」的格式(形如
T a_1 a_2 ... a_n),原生记录字面量类型、展开后为记录字面量的类型别名都不符合该要求。 - 你定义的
Obj是记录类型的别名,展开后就是{ id :: String }这类原生记录类型,不满足默认的实例格式要求,因此触发报错。 - 报错中提到的函数依赖是其他场景下的绕过方案,不适用于你当前的需求。
解决方案
有两种常用的解决方式:
方案1:开启FlexibleInstances扩展
在代码文件顶部添加编译指令开启FlexibleInstances扩展,该扩展专门用于放开实例头部的类型格式限制,允许任意具体类型出现在实例头中:
{-# LANGUAGE FlexibleInstances #-} class Codable param where getCodec :: Codec param type Obj = { id :: String } instance Codable Obj where getCodec = objCodec
如果是PureScript环境,同样开启FlexibleInstances扩展即可。
方案2:用newtype包装记录类型
如果不想开启语言扩展,可以用newtype对记录类型做一层包装,生成符合默认规则的自定义类型构造器:
class Codable param where getCodec :: Codec param newtype Obj = Obj { id :: String } instance Codable Obj where -- 若你的objCodec仅适配原生记录类型,这里可以加一层包装适配,比如: -- getCodec = contramap (\(Obj o) -> o) objCodec getCodec = objCodec
该方案不需要依赖语言扩展,同时还能为该记录类型提供独立的类型语义,避免和其他同结构的记录类型混淆类型类实例。
内容的提问来源于stack exchange,提问作者WHITECOLOR
相关产品推荐
相关产品推荐

