I recently learned that I can do the following in 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"))
This will give me the following:
["field1","field2","field3"]
How can I do the same thing for the values in a record, like this:
["5","Hello","World"]
I'm asking because I'm using Aeson
to take simple JSON like this:
{
"field1":5,
"field2":"Hello",
"field3":"World"
}
And generate Haskell code like this:
field1 :: Int
field1 = 5
field2 :: String
field2 = "Hello"
field3 :: String
field3 = "World"
How can I generically unwrap all the values in a given record in the same way I can unwrap the field names of my records?
Your first question can be answered. If you're happy to convert all the values of a datatype to strings, then you can indeed produce such a list with a generic programming library such as e.g. 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")
Now in GHCi:
GHCi> test
["5","\"Hello\"","\"world\""]
However, if your goal is to maintain the original types, then this is more difficult, as the result type will have to be a heterogeneous list (which in fact generics-sop
uses internally, before it is converted back into a normal list using hcollapse
).
It's not entirely clear to me what you really want to achieve. It's quite possible that there's a much more straight-forward solution.