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

How to generically extract field names and values in Haskell records

我最近了解到我可以在 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"))

这将给我以下内容:

["field1","field2","field3"]

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

["5","Hello","World"]

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

{
  "field1":5,
  "field2":"Hello",
  "field3":"World"
}

并像这样生成 Haskell 代码:

field1 :: Int
field1 = 5

field2 :: String
field2 = "Hello"

field3 :: String
field3 = "World"

我如何才能像解开记录的字段名称一样解开给定记录中的所有值?

你的第一个问题可以回答了。如果您乐于将数据类型的所有值转换为字符串,那么您确实可以使用通用编程库生成这样的列表,例如generics-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")

现在在 GHCi 中:

GHCi> test
["5","\"Hello\"","\"world\""]

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

回到正常列表

我不太清楚你真正想要实现的目标。很可能有更直接的解决方案。