假设数据类型的 GHC.Generic 类的实例应由 GHC 通过派生机制自动生成,但它不适用于行类型和具有隐式参数的匿名记录。因此,我尝试手动定义泛型实例,并开始实验,使用 GHCi 复制常规数据类型的泛型实例来获取泛型表示,作为准备步骤,但即使在这里,我也面临来自类型检查器的无法解释的错误。
> 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)))
基于上述 GHCi 输出的 Point 通用实例:
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}}})} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
我不明白问题出在哪里,因为 type family application
Rep Point x
应该等于它的值。
GHC版本是9.8.1
启用的扩展列表:
DataKinds LambdaCase ImplicitParams OverloadedLabels OverloadedStrings TupleSections TypeFamilies UnicodeSyntax GADTs PolyKinds RankNTypes TypeOperators TypeApplications
更新:
感谢@leftaroundabout。 GHCi 生成错误的表示。
以下实现满足类型检查器的要求。
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
。这是 :+:
的构造函数,这对您的类型没有意义。
这个定义编译:
from r = M1 {unM1 = M1 {unM1 = M1 {unM1 = K1 {unK1 = x r}} :*: M1 {unM1 = K1 {unK1 = y r}}}}
或者,更易读的是,
from r = M1 . M1 $ M1 (K1 $ x r) :*: M1 (K1 $ y r)
不过,我相当怀疑写这样一个实例是否明智。一般来说,泛型实例的全部要点是它允许您定义类实例,而不需要编写处理类型结构的特殊代码。如果您无论如何都要编写这样的代码,为什么不立即实例化感兴趣的类呢?如果您的类型很不寻常,不支持派生的 Generic
实例,那么这可能更合适。