我有一个这样的记录类型:

data VehicleState f = VehicleState
                      {
                        orientation :: f (Quaternion Double),
                        orientationRate :: f (Quaternion Double),
                        acceleration :: f (V3 (Acceleration Double)),
                        velocity :: f (V3 (Velocity Double)),
                        location :: f (Coordinate),
                        elapsedTime :: f (Time Double)
                      }
                    deriving (Show)

这很酷,因为我可以在其中拥有各种元数据的VehicleState Signal,在我具有每个信号的VehicleState (Wire s e m ())语义的netwire或在某个时间观察到的实际值的VehicleState Identity

通过在每个字段上映射VehicleState Identity来定义在VehicleState'runIdentity之间来回映射的好方法吗?
data VehicleState' = VehicleState'
                      {
                        orientation :: Quaternion Double,
                        orientationRate :: Quaternion Double,
                        acceleration :: V3 (Acceleration Double),
                        velocity :: V3 (Velocity Double),
                        location :: Coordinate,
                        elapsedTime :: Time Double
                      }
                    deriving (Show)

显然,编写一个很简单,但是在我的实际应用程序中我实际上有几种类型,并且我不断添加或删除字段,所以这很繁琐。

我正在写一些能做到这一点的模板Haskell,只是想知道我是否正在重新发明轮子。

最佳答案

如果您不反对类型族并且不需要太多类型推断,那么实际上可以摆脱使用单个数据类型的麻烦:

import Data.Singletons.Prelude

data Record f = Record
  { x :: Apply f Int
  , y :: Apply f Bool
  , z :: Apply f String
  }

type Record' = Record IdSym0

test1 :: Record (TyCon1 Maybe)
test1 = Record (Just 3) Nothing (Just "foo")

test2 :: Record'
test2 = Record 2 False "bar"
Apply类型族在singletons包中定义。可以应用于
该包中还定义了各种类型的函数(当然,您可以定义自己的
自己的)。 IdSym0具有Apply IdSym0 x减少为纯x的属性。和TyCon1具有Apply (TyCon1 f) x减少为f x的属性。

正如所证明的test1test2,这允许您使用两种版本的数据类型。但是,您需要
现在为大多数记录键入注释。

10-08 05:20