0

Suppose I have a prefix p and list of strings ss. I would like to generate a record field name, p ++ s, for each of the strings s in ss.

data Example = Example
  { field1 :: String
  , field2 :: String
  -- the rest of the fields are generated
  , prefixString1 :: Maybe String
  , prefixString2 :: Maybe String
  , prefixString3 :: Maybe String
  -- ...
  } deriving (Eq, Show)

I'm writing an API client for an API I do not own. Provided certain query parameters, the endpoint will provide additional parameters on the object.

-- without query param
{
  "field_1": "",
  "field_2": ""
}

-- with query param "x"
{
  "field_1": "",
  "field_2": "",
  "field_1_x": "",
  "field_2_x": ""
}

-- with query param "y"
{
  "field_1": "",
  "field_2": "",
  "field_1_y": "",
  "field_2_y": ""
}

There are ~30 different values the query parameter can be so I'd end up have a huge record of over 60 fields that are all basically the same except the suffix is different.

Wilfred
  • 799
  • 2
  • 16
  • 26
  • 2
    Why not just make the last field a `[Maybe String]` and stick them all in there? – Carcigenicate Jan 07 '18 at 16:30
  • 2
    This is maybe possible with Template Haskell (no idea), but otherwise unlikely. – hnefatl Jan 07 '18 at 16:49
  • 1
    @hnefatl The OP added the TH tag, so I think it's asking for that. It should be clarified in the question, though, since it's an important detail. – chi Jan 07 '18 at 18:12
  • @Carcigenicate I would except this is for an API client that consumes an API I have not control over. – Wilfred Jan 07 '18 at 19:00
  • @chi I was thinking that maybe it was possible with TH but the recommendations I've seen say to only use it when there is no other way. – Wilfred Jan 07 '18 at 19:00
  • 2
    Nothing but TH can generate record fields. Also note that TH runs at compile time, you can't generate record fields at runtime in any way, since that would break static typing. Perhaps you should share why do you want to do this, instead of using e.g. `Data.Map.Map` for the mapping. – chi Jan 07 '18 at 19:28
  • @chi I've added an explanation to the question. I'm hesitant about using `Data.Map.Map` because with a record I can use the `deriveJSON` splice from Data.Aeson.TH`. Also I think providing a record type to the user is better UX. – Wilfred Jan 07 '18 at 20:40
  • 2
    Seems like you're looking for extensible records. However, this question lacks specifics. Generating a type from some specification is fairly straightforward with TH. The real question is what sorts of functions do you want to write which consume or produce such records. If you are just interested in representing JSON-like objects, just use a `Map` or even something like `Value` from `aeson`. There is no barrier to writing a 'record-like' interface for these types (this is essentially the problem solved by `lens`). – user2407038 Jan 07 '18 at 21:07

1 Answers1

0

I don't think so.

data means you are defining a new data type. Haskell is a static programming language meaning that all types are known at compile time.

Use a List, Tree or some other data structure you can expand/ work on at runtime.

Idea:
If these attributes have all the same suffix, save the suffix and the other strings in a list. If you need them you just combine the suffix & strings.

Maybe something like this:

data A = A [String] String

create :: A -> [String]
create (A ss suff) = create' ss suff
  where create' [] _ = []
        create' a b = ((head a) ++ b) : create' (tail a) b