在通用 SOP 中检索记录功能
Retrieving record function in generic SOP
在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
将 fieldName
作为字符串。所以,我没有看到任何方法来获得实际函数 frec :: Rec -> Int
和 srec :: Rec -> Maybe String
。我也看过 show example 但它不使用记录功能。
将感谢有关如何获取记录函数(可以是 HList '[(Rec -> Int), (Rec -> Maybe String)]
类型的 HList)的指示。
问题补遗
关于如何使用 user2407038 提出的方法从投影中获取功能,我陷入了类型结。因此,我想进一步补充问题:我们如何在 Rec
构造函数上使用 SOP
方法构建如下函数 - 我们在此处同时使用记录字段名称和函数:
[ ("frec" ++) . show . frec, ("srec" ++) . show . srec]
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
的产生式表示之和是一个单例列表(一个构造函数)。 return 类型(可能)是列表 r
(记录字段类型列表)上的一个产品,其中每个类型有一个 FieldInfo x
和一个 t -> x
x
在 r
中。
一个实现是
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
这里函数判断给定的数据类型是否真的是一条记录,否则returns Nothing
。如果它是一条记录,将记录字段和 projections
(由库定义)压缩在一起,它定义了任意通用产品的投影,对于您的类型,它实际上只是 NP '[ Code Rec -> Int, Code Rec -> Maybe String ]
。剩下的就是将 from
函数与每个投影组合起来以获得 "real" 投影。其余的(Fn
、unSOP
等)只是身份。
原来你只是想要记录投影函数,没有函数名,这就更简单了。现在这个函数不是部分的——任何一种构造函数类型都有 "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
在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
将 fieldName
作为字符串。所以,我没有看到任何方法来获得实际函数 frec :: Rec -> Int
和 srec :: Rec -> Maybe String
。我也看过 show example 但它不使用记录功能。
将感谢有关如何获取记录函数(可以是 HList '[(Rec -> Int), (Rec -> Maybe String)]
类型的 HList)的指示。
问题补遗
关于如何使用 user2407038 提出的方法从投影中获取功能,我陷入了类型结。因此,我想进一步补充问题:我们如何在 Rec
构造函数上使用 SOP
方法构建如下函数 - 我们在此处同时使用记录字段名称和函数:
[ ("frec" ++) . show . frec, ("srec" ++) . show . srec]
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
的产生式表示之和是一个单例列表(一个构造函数)。 return 类型(可能)是列表 r
(记录字段类型列表)上的一个产品,其中每个类型有一个 FieldInfo x
和一个 t -> x
x
在 r
中。
一个实现是
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
这里函数判断给定的数据类型是否真的是一条记录,否则returns Nothing
。如果它是一条记录,将记录字段和 projections
(由库定义)压缩在一起,它定义了任意通用产品的投影,对于您的类型,它实际上只是 NP '[ Code Rec -> Int, Code Rec -> Maybe String ]
。剩下的就是将 from
函数与每个投影组合起来以获得 "real" 投影。其余的(Fn
、unSOP
等)只是身份。
原来你只是想要记录投影函数,没有函数名,这就更简单了。现在这个函数不是部分的——任何一种构造函数类型都有 "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