Super generic F# - maybe these are HKTs?

Viewed 104

So, I'm working on a new generic CLI args parser (mostly for my own benefit, we'll see if I come up with something useful worth publishing).

Let's just say to start with that I have a function that has this signature: (ArgumentConfiguration<'a> -> string array -> 'a * string array - so in other words, I have a function that will extract out and give me the value of a particular configured argument, and the remaining elements of the string array. The generic type 'a is unbounded, so it could be int, float, Foo, whatever. There's a Parse function in the config type that returns whatever I need.

Ok cool. Next thing is to have a data structure the user can input that contains all of those parsers, and a function that will take that structure and return the same "shape" of structure but instead of ArgumentConfiguration<'a> it will just return 'a. Here's a more concrete example:

(* Input Type *)
type ArgumentInput = {
  A: ArgumentConfiguration<float>
  B: ArgumentConfiguration<int>
  C: ArgumentConfiguration<boolean>
}

(* Expected return type that I don't want to specify - I want it inferred *)
type ParserResult = {
  A: float
  B: int
  C: boolean
}

The key is this: I want this to be as strongly typed as possible, but obviously I have different types of different arguments all over the place. I'm open to doing different structures too - perhaps a Map might work? even a Sequence? Collections seem like not the right answer though if I'm going to have a ArgumentConfiguration<float> next to an ArgumentConfiguration<int> etc.

So given all of this info, here are my questions:

  1. What kind of data structure would work well to store these data so that the data and type can be transformed in a function?
  2. How would the function signature work?
    • Because I'm familiar with Typescript and the way it does things (though I want this in F#) the signature I imagine would be like type ParserFn = (config: Record<string, ArgumentConfiguration<any>>) => (args: string[]) => Record<string, any>; except that nukes the types for each record entry (and I don't think there's a good workaround in Typescript for that either; just using TS since I know it better)

Being enthusiastic about advanced FP concepts but not necessarily the most experienced, I wonder if I've stumbled on a limitation of the F# type system (would a new custom Type Provider help me?), and whether a language like Haskell or even Idris might be required to fully express the logic I'm looking at writing.

0 Answers
Related