如何在Haskell记录中一般提取字段名称和值

car*_*emb 2 generics haskell record

我最近了解到我可以在Haskell中执行以下操作:

{-# LANGUAGE DeriveDataTypeable #-}

import Data.Data

data MyRecord = MyRecord
  { field1 :: Int
  , field2 :: String
  , field3 :: String
  } deriving (Show,Eq,Data,Typeable)

main = print $ constrFields (toConstr (MyRecord 5 "Hello" "World"))
Run Code Online (Sandbox Code Playgroud)

这将给我以下内容:

["field1","field2","field3"]
Run Code Online (Sandbox Code Playgroud)

如何对记录中的值执行相同的操作,如下所示:

["5","Hello","World"]
Run Code Online (Sandbox Code Playgroud)

我问,因为我正在使用Aeson像这样的简单JSON:

{
  "field1":5,
  "field2":"Hello",
  "field3":"World"
}
Run Code Online (Sandbox Code Playgroud)

并生成如下的Haskell代码:

field1 :: Int
field1 = 5

field2 :: String
field2 = "Hello"

field3 :: String
field3 = "World"
Run Code Online (Sandbox Code Playgroud)

我怎样才能解开给定记录中的所有值,就像我可以解开记录的字段名称一样?

kos*_*kus 8

你的第一个问题可以回答.如果你感到快乐的数据类型为字符串的所有值的转换,那么你确实可以用一个通用的编程库诸如这样的列表泛型-SOP:

{-# LANGUAGE DeriveGeneric, FlexibleContexts #-}

import qualified GHC.Generics as G
import Generics.SOP

data MyRecord = MyRecord
  { field1 :: Int
  , field2 :: String
  , field3 :: String
  } deriving (Show, Eq, G.Generic)

instance Generic MyRecord

stringValues ::
     (Generic a, All2 Show (Code a))
  => a -> [String]
stringValues a =
  hcollapse (hcmap (Proxy :: Proxy Show) (\ (I x) -> K (show x)) (from a))

test :: [String]
test = stringValues (MyRecord 5 "Hello" "world")
Run Code Online (Sandbox Code Playgroud)

现在GHCi:

GHCi> test
["5","\"Hello\"","\"world\""]
Run Code Online (Sandbox Code Playgroud)

但是,如果您的目标是维护原始类型,那么这将更加困难,因为结果类型必须是异构列表(实际上在generics-sop内部使用,在使用之前将其转换回正常列表hcollapse).

对我来说,你真正想要实现的目标并不完全清楚.很可能有一个更直接的解决方案.

  • @danidiaz原则上,是的.至少从'vinyl-0.5`开始,他们的`Rec`类型在`generics-sop`中与`NP`在结构上是同构的.因此转换应该很容易,理论上,两个库都可以合并.但到目前为止,做可扩展记录并不是"generics-sop"的主要关注点. (3认同)