我有一个像这样的记录类型:
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
,这允许您的数据类型的两个版本。但是,您需要现在为大多数记录键入注释。
关于haskell - 在记录上映射身份仿函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24922375/