我有一个这样的记录类型:
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
的属性。正如所证明的
test1
和test2
,这允许您使用两种版本的数据类型。但是,您需要现在为大多数记录键入注释。