Haskell 记录上的映射恒等函子
我有一个这样的记录类型:Haskell 记录上的映射恒等函子,haskell,functor,template-haskell,Haskell,Functor,Template Haskell,我有一个这样的记录类型: data VehicleState f = VehicleState { orientation :: f (Quaternion Double), orientationRate :: f (Quaternion Double), acceleration :: f (V3 (Acc
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信号
其中我有各种元数据,我可以有一个VehicleState(Wire s e m())
其中我有每个信号的netwire
语义,或者我可以有一个VehicleState标识
,其中我有在特定时间观察到的实际值
是否有一种在车辆状态标识
和车辆状态
之间来回映射的好方法,通过映射每个字段上的运行标识
来定义
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
类型族。它可以应用于
该包中还定义了各种类型的函数(当然,您可以定义
自己的)。IdSym0
的属性是Apply IdSym0 x
减少为普通的x
。及
TyCon1
具有Apply(tycon1f)x
减少为fx
的属性
正如
test1
和test2
,这允许您的数据类型的两个版本。然而,你需要
现在为大多数记录键入注释。您可能可以使用GHC泛型实现这一点,但我不知道它是否比TH更简单。既然我有TH的经验,那也是我的选择。我要考虑的是:根本不要使用
VehicleState'
,为Identity
和runIdentity
做一个简短的别名。我知道,不太好。Identity
是一种新类型,所以cast::VehicleState Identity->VehicleState';在这种情况下,cast=unsafeccerce
实际上是安全的。(显然,反过来也是一样)我同意@luqui的建议;我用过它,效果很好。只需导出透镜以访问车辆状态的每个字段
,然后您就可以通过使用透镜组合包装的
或展开的
来访问身份包装的变体。@JohnL,如果您有时间,您能详细说明一下吗?我还不懂镜头。