Search code examples
haskellalgebraic-data-types

Storing type fields in a list


Hello i am faced with the following problem. I have a data type with multiple fields.I need to enumerate them and store them in a collection for further mapping.

data Worker=Worker{
        age::Int,
        name::String,
        title::Title,
        income::Int
    }


    data Title=Manager | Dev | Tester deriving (Show)



    instance Show Worker where 
        show w=let !names=["age","name", "title","income"] 
                   !props= [age,name,title,income]  in   -- Do i need to define another new type to be able to flat them down to a list?
            "{"++intercalate "," (zipWith (\x y-> x++":"++ y w) names props)++"}"

Where can i store all all properties (methods)to be able to further use them as a parameter in a higher order function on a given variable of type Worker in our case.


Solution

  • You can get sort of close to the thing you're looking for, but it's not going to be pretty.

    We can use RecordWildCards to bring all of the accessor names into scope as though they were ordinary variables, but that still introduces a new problem.

    -- Not runnable Haskell code
    foo Worker {..} = let names = ["age", "name", "title", "income"]
                          props = [age, name, title, income]
                      in ...
    

    We're pattern matching on Worker {..}, which introduces a bunch of accessor names into the local scope. However, props is trying to be a heterogeneous list, which Haskell does not allow. It contains two integers, a string, and a title, whereas Haskell lists are only supposed to contain one type.

    Since you're trying to show each field, you're going to have to apply show to each element by hand. Like I said, this is going to be a bit ugly.

    foo Worker {..} = let names = ["age", "name", "title", "income"]
                          props = [show age, show name, show title, show income]
                      in ...
    

    It may look like we can do map show [age, name, title, income], but we can't. That list still wouldn't be valid, and we're applying three different show functions here (they just happen to share a name), so we can't meaningfully map the same show over each element.

    However, as the comments say, your best bet is to familiarize yourself with a proper JSON library, and Aeson is easily the best choice in Haskell for that sort of thing.