4

Sum of Products方法中,如何检索记录功能?下面带有记录数据类型 ( ) 的示例代码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

让我们DataTypeInfo 在 ghci 提示符下查看:

*Main> datatypeInfo (Proxy :: Proxy Rec)
ADT "Main" "Rec" (Record "Rec" (FieldInfo "frec" :* (FieldInfo "srec" :* Nil)) :* Nil)

我们看到了,frec并且srec都是FieldInfo具有构造函数的类型,该构造函数FieldInfo采用fieldNameas 字符串。所以,我看不到任何方法来获得实际的功能frec :: Rec -> Intsrec :: Rec -> Maybe String. 我还查看了显示示例,但它不使用记录功能。

将欣赏有关如何获取记录函数的指针(可能是 HList 类型HList '[(Rec -> Int), (Rec -> Maybe String)]))。

问题的附录

我被困在关于如何使用 user2407038 提出的方法从投影中获取功能的类型结中。所以,我想进一步补充这个问题:我们如何使用构造函数的SOP方法Rec构建如下函数 - 我们使用记录字段名称以及此处的函数:

[ ("frec" ++) . show . frec, ("srec" ++) . show . srec] 
4

1 回答 1

5

generics-sop库实现了用于处理产品总和的通用组合器,因此您应该使用这些组合器编写这样的函数。

有一个问题 -generics-sop在类型级别上没有关于记录与构造函数的任何信息,所以你的函数仍然是部分的(除非你去挖掘 GHC 泛型Rep)。

对于这个例子,我将只使用部分函数路线。

首先,您需要这种数据类型:

data (:*:) f g x = f x :*: g x deriving (Show, Eq, Ord, Functor) 

似乎它应该包含在库中,但它不是(或者我找不到它)。

函数的类型将是

recordSelectors :: forall t r . (Code t ~ '[ r ], Generic t, HasDatatypeInfo t) 
                => Proxy t -> Maybe (NP (FieldInfo :*: (->) t) r)

约束Code t ~ '[ r ]简单地说,产生式表示的总和t是一个单例列表(一个构造函数)。返回类型(可能)是列表r(记录字段类型列表)上的产品,其中每个类型都有aFieldInfo x和 a 。t -> xxr

一种实现是

  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 

此处函数确定给定数据类型中确实是一条记录,否则返回Nothing. 如果它是一条记录,请将记录字段和(由库定义)压缩在一起projections,它定义了任意通用产品的投影,这基本上只NP '[ Code Rec -> Int, Code Rec -> Maybe String ]适用于您的类型。剩下的就是from用每个投影组合函数以获得“真实”投影。其余的(Fn,unSOP等)只是身份。


因为事实证明你只想要记录投影函数,没有函数名称,这更简单。现在该函数不是部分的——任何一种构造函数类型都有“记录投影”。

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 
于 2016-03-28T02:24:08.113 回答