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

时间:2016-04-02 05:05:11

标签: haskell generics 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"))

这将给我以下内容:

["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"

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

1 个答案:

答案 0 :(得分:8)

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

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