在记录上映射身份仿函数

Dou*_*ean 9 haskell functor template-haskell

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

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)
Run Code Online (Sandbox Code Playgroud)

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

有没有一种很好的方法来在每个字段之间来回映射VehicleState IdentityVehicleState'定义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)
Run Code Online (Sandbox Code Playgroud)

显然写一个是微不足道的,但实际上我在实际应用程序中有几个这样的类型,我不断添加或删除字段,所以这很乏味.

我正在编写一些模板Haskell来做它,只是想知道我是否正在重新发明轮子.

kos*_*kus 4

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

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"
Run Code Online (Sandbox Code Playgroud)

类型族在singletonsApply包中定义。它可以应用于该包中定义的各种类型函数(当然,您可以定义自己的函数)。其具有简化为简单的性质。并 具有简化为 的性质。IdSym0Apply IdSym0 xxTyCon1Apply (TyCon1 f) xf x

正如 test1和所示test2,这允许使用两种版本的数据类型。但是,现在大多数记录都需要类型注释。