简体   繁体   English

检索通用SOP中的记录功能

[英]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. 我们看到frecsrec都是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 -> Intsrec :: 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. 其余的( FnunSOP等)只是身份。


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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM