[英]Retrieving record function in generic SOP
In Sum of Products
approach, how would one retrieve the record function? 在
Sum of Products
方法中,如何检索记录功能? An example code below with record datatype ( ghc 7.10.3
): 下面带有记录数据类型(
ghc 7.10.3
)的示例代码:
{-# LANGUAGE DeriveGeneric #-}
import qualified GHC.Generics as GHC
import Generics.SOP
data Rec = Rec { frec :: Int, srec :: Maybe String}
deriving (Show, GHC.Generic)
instance Generic Rec -- empty
instance HasDatatypeInfo Rec
Let us see DataTypeInfo
at ghci prompt: 让我们在ghci提示符下看到
DataTypeInfo
:
*Main> datatypeInfo (Proxy :: Proxy Rec)
ADT "Main" "Rec" (Record "Rec" (FieldInfo "frec" :* (FieldInfo "srec" :* Nil)) :* Nil)
We see that frec
and srec
are both of type FieldInfo
which has a constructor FieldInfo
which takes the fieldName
as string. 我们看到
frec
和srec
都是FieldInfo
类型,它有一个构造函数FieldInfo
,它将fieldName
作为字符串。 So, I don't see any way to get the actual functions frec :: Rec -> Int
and srec :: Rec -> Maybe String
. 所以,我没有看到任何方法来获取实际的函数
frec :: Rec -> Int
和srec :: Rec -> Maybe String
。 I also looked at show example but it doesn't use record functions. 我也查看了show示例,但它没有使用记录功能。
Will appreciate pointers on how to get the record functions (could be HList of type HList '[(Rec -> Int), (Rec -> Maybe String)]
)). 将会了解如何获取记录函数的指针(可能是HList类型
HList '[(Rec -> Int), (Rec -> Maybe String)]
))。
Addendum to the question 该问题的补遗
I am tied up in the type knots about how to get the functions out of the projections using the approach user2407038 has laid out. 关于如何使用user2407038设计的方法从投影中获取函数,我陷入类型结。 So, I will like to add to the question further: how do we build a function like below using
SOP
approach on Rec
constructor - we use both record field name as well as the function here: 所以,我想进一步补充这个问题:我们如何在
Rec
构造函数上使用SOP
方法构建类似下面的函数 - 我们同时使用记录字段名称和函数:
[ ("frec" ++) . show . frec, ("srec" ++) . show . srec]
The generics-sop
library implements general combinators for working with sums of products, so you should write such a function using those combinators. generics-sop
库实现了用于处理产品总和的通用组合器,因此您应该使用这些组合器编写这样的函数。
There is one issue - generics-sop
does not have any information about records vs. constructors on the type level, so your function will be still be partial (unless you go digging in the GHC generics Rep
). 有一个问题 -
generics-sop
在类型级别上没有关于记录与构造函数的任何信息,因此你的函数仍然是部分的(除非你去挖掘GHC泛型Rep
)。
For this example I'll just go with the partial function route. 对于这个例子,我将使用部分功能路由。
First, you need this datatype: 首先,您需要以下数据类型:
data (:*:) f g x = f x :*: g x deriving (Show, Eq, Ord, Functor)
It seems like it should be included in the library, but it isn't (or I can't find it). 它似乎应该包含在库中,但它不是(或者我找不到它)。
The type of the function will be 函数的类型将是
recordSelectors :: forall t r . (Code t ~ '[ r ], Generic t, HasDatatypeInfo t)
=> Proxy t -> Maybe (NP (FieldInfo :*: (->) t) r)
The constraint Code t ~ '[ r ]
simply says that the sum of productions representation of t
is a singleton list (one constructor). 约束
Code t ~ '[ r ]
简单地说t
的产生表示的总和是单个列表(一个构造函数)。 The return type is (maybe) a product over the list r
(the list of record field types) where there is a FieldInfo x
and a t -> x
for each type x
in r
. 返回类型(可能)是列表
r
(记录字段类型列表)上的产品,其中有一个FieldInfo x
和一个t -> x
用于r
每个类型x
。
One implementation is 一个实现是
case datatypeInfo (Proxy :: Proxy t) of
ADT _ _ (Record _ fields :* Nil) -> Just $
hzipWith (\nm (Fn prj) -> nm :*: (unI . prj . K . (\(Z x) -> x) . unSOP . from))
fields
projections
_ -> Nothing
Here the function determines in the given datatype is really a record, and otherwise returns Nothing
. 这里函数确定给定的数据类型实际上是一个记录,否则返回
Nothing
。 If it is a record, zip togther the record fields and the projections
(defined by the library), which defines projections for an arbitrary generic product, which is essentially just NP '[ Code Rec -> Int, Code Rec -> Maybe String ]
for your type. 如果它是一个记录,则压缩记录字段和
projections
(由库定义),它定义任意通用产品的投影,基本上只是NP '[ Code Rec -> Int, Code Rec -> Maybe String ]
为你的类型。 All that is left is to compose the from
function with each projection to get the "real" projections. 剩下的就是用每个投影组成
from
函数来获得“真实”投影。 The rest ( Fn
, unSOP
, etc.) are just identities. 其余的(
Fn
, unSOP
等)只是身份。
Since it turns out you just want the record projection functions, sans function names, this is even simpler. 事实证明,你只需要记录投影功能,没有功能名称,这甚至更简单。 And now the function isn't partial - any one constructor type has "record projections".
现在函数不是局部的 - 任何一个构造函数类型都有“记录投影”。
recordSelectors' :: forall t r . (Code t ~ '[ r ], Generic t)
=> Proxy t -> NP ((->) t) r
recordSelectors' _ = hmap (\(Fn prj) -> unI . prj . K . (\(Z x) -> x) . unSOP . from)
projections
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.