对product类型的访问器进行泛型迭代



我使用generics-sop编写了以下函数。它所做的是,给定一个product类型的值,遍历它的所有成员,对所有这些成员应用一个函数,然后输出结果列表:

import Generics.SOP qualified as SOP
import Generics.SOP hiding (Generic)
productToList :: forall c a t xs. (
IsProductType a xs, 
SOP.Generic a, 
ProductCode a ~ xs, 
All c xs
) 
=> (forall b. c b => b -> t) -> a -> [t]
productToList f = hcollapse . hcmap (Proxy :: Proxy c) (mapIK f) . productTypeFrom

下面是一些用法示例:

import Generics.SOP qualified as SOP
import Generics.SOP hiding (Generic)
data MyNums = MyNums { anInt :: Int, anInteger :: Integer, aFloat :: Float }
deriving stock Generic
deriving anyclass SOP.Generic
class (Eq a, Num a) => EqNum a 
instance (Eq a, Num a) => EqNum a 
c = MyNums { anInt = 0, anInteger = 5, aFloat = 7.2 }
f :: (Eq a, Num a) => a -> Bool
f x = x == 0
y :: [Bool]
y = genericProductToList @EqNum f c

这将输出列表[True, False, False]

到目前为止一切顺利。但是现在我正在尝试使一些代码泛型,我需要的签名略有不同。而不是:

productToList          :: ... => (forall b. c b => b -> t) -> a -> [t]

我想要

productAccessorsToList :: ... => (forall b. c b => (a -> b) -> t) -> [t]

基本上不是传递结构体的值并遍历成员,在本例中没有值,但我想遍历类型的访问器函数。

我基本上把aforall外面移到了forall里面。

productAccessorsToList的实现是什么?

基本功能包含在projections中。操纵。

projectionsToList ::
forall c a t xs.
( IsProductType a xs
, SOP.Generic a
, ProductCode a ~ xs
, All c xs
)
=> (forall b. c b => (a -> b) -> t)
-> [t]
projectionsToList f =
hcollapse @_ @_ @NP @xs
$ hcmap (Proxy @c) adjust (projections @_ @I)
where
adjust :: forall x. c x => (K (NP I xs) -.-> I) x -> K t x
adjust p = K $ f $ unI . apFn p . K . productTypeFrom

你可以恢复productToList从这个,但我不相信它工作的其他方式

productToList' ::
forall c a t xs.
( IsProductType a xs
, SOP.Generic a
, ProductCode a ~ xs
, All c xs
) 
=> (forall b. c b => b -> t)
-> a -> [t]
productToList' f x = projectionsToList @c @a (f . ($ x))
-- would probably be slower than productToList

最新更新