如何在 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
).
回到正常列表
我不太清楚你真正想要实现的目标。很可能有更直接的解决方案。
我最近了解到我可以在 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
).
我不太清楚你真正想要实现的目标。很可能有更直接的解决方案。