如何手动定义GHC.Generic实例?类型检查错误排查
手动实现GHC.Generic实例的问题排查与解决
GHC通常会通过deriving机制自动为数据类型生成GHC.Generic类的实例,但该机制对带隐式参数的行类型和匿名记录无效。因此尝试手动定义Generic实例,先以常规数据类型Point做实验:
通过GHCi获取Generic表示
在GHCi中执行以下命令,获取Point的Generic结构:
> import GHC.Generics > data Point = Point { x :: Int, y :: Int } deriving (Show, Eq, Generic) > from (Point 1 2) M1 {unM1 = M1 {unM1 = M1 {unM1 = K1 {unK1 = 1}} :*: M1 {unM1 = K1 {unK1 = 2}}}} > :i Rep Point type instance Rep Point = D1 (MetaData "Point" "RowTypeDemo.ImplicitParamsAsAlternativeToRowType" "row-type-demo-0.0.1-inplace" False) (C1 (MetaCons "Point" PrefixI True) (S1 (MetaSel (Just "x") NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 Int) :*: S1 (MetaSel (Just "y") NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 Int)))
手动实现Generic实例并报错
复制上述表示手动实现Generic实例:
data Point = Point { x :: Int, y :: Int } deriving (Show, Eq) instance Generic Point where type Rep Point = D1 (MetaData "Point" "RowTypeDemo.ImplicitParamsAsAlternativeToRowType" "row-type-demo-0.0.1-inplace" False) (C1 (MetaCons "Point" PrefixI True) (S1 (MetaSel (Just "x") NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 Int) :*: S1 (MetaSel (Just "y") NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 Int))) from :: Point -> Rep Point x from r = M1 {unM1 = L1 (M1 {unM1 = M1 {unM1 = K1 {unK1 = x r}} :*: M1 {unM1 = K1 {unK1 = y r}}})}
类型检查器报错如下:
• Couldn't match type: M1 i0 c0 (M1 i1 c1 (K1 i2 Int) :*: M1 i3 c2 (K1 i4 Int)) :+: g0 with: M1 C (MetaCons "Point" PrefixI True) (S1 (MetaSel (Just "x") NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 Int) :*: S1 (MetaSel (Just "y") NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 Int)) Expected: Rep Point x Actual: M1 D (MetaData "Point" "RowTypeDemo.ImplicitParamsAsAlternativeToRowType" "row-type-demo-0.0.1-inplace" False) (M1 i0 c0 (M1 i1 c1 (K1 i2 Int) :*: M1 i3 c2 (K1 i4 Int)) :+: g0) x • In the expression: M1 {unM1 = L1 (M1 {unM1 = M1 {unM1 = K1 {unK1 = x r}} :*: M1 {unM1 = K1 {unK1 = y r}}})} In an equation for ‘from’: from r = M1 {unM1 = L1 (M1 {unM1 = M1 {unM1 = K1 {unK1 = x r}} :*: M1 {unM1 = K1 {unK1 = y r}}})} In the instance declaration for ‘Generic Point’ | 87 | from r = M1 {unM1 = L1 (M1 {unM1 = M1 {unM1 = K1 {unK1 = x r}} :*: M1 {unM1= K1 {unK1 = y r}}})} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
使用GHC版本为9.8.1,启用的扩展包括DataKinds、LambdaCase等。
问题修正
最初误以为GHCi生成的表示有误,后来发现是误用了和类型表示的L1,修正后的实现通过类型检查:
from :: Point -> Rep Point x from r = M1 {unM1 = (M1 {unM1 = M1 {unM1 = K1 {unK1 = x r}} :*: M1 {unM1 = K1 {unK1 = y r}}})} to (M1 {unM1 = (M1 {unM1 = M1 {unM1 = K1 {unK1 = xx}} :*: M1 {unM1 = K1 {unK1 = yy}}})}) = Point xx yy
确认错误原因:误用了和类型表示的L1构造函数,而Point是单构造函数类型,不需要用L1包裹构造器的Generic表示。
内容的提问来源于stack exchange,提问作者Daniil Iaitskov
相关产品推荐
相关产品推荐

