如何在一个函数中以两种方式使用相同的记录选择器?镜头?



我有一些数据,这些数据基于类型参数具有不同的表示形式,例如桑迪·马奎尔(Sandy Maguire(的高级种类数据。下面是两个示例:

wholeMyData :: MyData Z
wholeMyData = MyData 1 'w'
deltaMyData :: MyData Delta
deltaMyData = MyData Nothing (Just $ Left 'b')

我在下面给出了一些实现细节,但首先是实际问题。

我经常想获取数据字段,通常是通过本地定义,例如:

let x = either (Just . Left . myDataChar) myDataChar -- myDataChar a record of MyData

这种情况经常发生,我想做一个标准的运算器,

getSubDelta :: ( _ -> _ ) -> Either a b -> Maybe (Either c d)
getSubDelta f = either (Just . Left . f) f

但是填写签名是有问题的。简单的解决方案是仅提供两次记录选择器功能,

getSubDelta :: (a->c) -> (b->d) -> Either a b -> Maybe (Either c d)
getSubDelta f g = either (Just . Left . f) g

但这是不体面的。所以我的问题。有没有办法填写上面的签名?我假设可能有一个基于镜头的解决方案,那会是什么样子?它对深度嵌套数据有帮助吗?我不能依赖数据类型始终是单个构造函数,那么棱镜呢?遍历?我的镜头游戏很弱,所以我希望在继续之前得到一些建议。

谢谢!


一些背景。我定义了一种通过混合GHC执行"增量"的通用方法。泛型和类型族。要点是在数据类型的定义中使用类型族。然后,根据类型的参数化方式,记录将表示整个数据或对现有数据的更改。

例如,我使用DeltaPoints定义业务数据。

MyData f = MyData { myDataInt  :: DeltaPoint f Int
, myDataChar :: DeltaPoint f Char} deriving Generic

DeltaPoints在库中实现,并且具有不同的DeltaZ状态形式。

data DeltaState = Z | Delta deriving (Show,Eq,Read)
type family DeltaPoint (st :: DeltaState) a where
DeltaPoint Z      a = a
DeltaPoint Delta  a = Maybe (Either a (DeltaOf a)) 

所以DeltaPoint Z a只是原始数据,a,而DeltaPoint Delta a可能存在,也可能不存在,如果存在,则替换原始数据(Left(或更新(DeltaOf a(。

运行时增量功能封装在类型类中。

class HasDelta a where
type DeltaOf a
delta :: a -> a -> Maybe (Either a (DeltaOf a))
applyDeltaOf :: a -> DeltaOf a -> Maybe a

通过使用泛型,我通常可以通过以下方式获得增量功能:

instance HasDelta (MyData Z) where
type (DeltaOf (MyData Z)) = MyData Delta

我想你可能想要:

{-# LANGUAGE RankNTypes #-}
getSubDelta :: (forall f . (dat f -> DeltaPoint f fld))
-> Either (dat Z) (dat Delta)
-> Maybe (Either (DeltaPoint Z fld) (DeltaOf fld))
getSubDelta sel = either (Just . Left . sel) sel

给:

x :: Either (MyData Z) (MyData Delta) 
-> Maybe (Either (DeltaPoint Z Char) (DeltaOf Char))
x = getSubDelta myDataChar
-- same as: x = either (Just . Left . myDataChar) myDataChar

最新更新