I have a Map whose keys may take a variety of shapes (I am using the word "shapes" loosely). In order to handle this I created a discriminated union (DU):
type AuxDataKey =
| OneString of string
| TwoStrings of string * string
| OneStringInt of string * int
| TwoStringsInt of string * string * int
| OneStringTwoInts of string * int * int
| TwoStringsTwoInts of string * string * int * int
type AuxData = Map<AuxDataKey,AuxDataItem>
A key can be created in this way:
let key = AuxDataKey.TwoStringsInt("Vol", ticker, count)
and information can be retrieved from a key created on-the-fly:
let vols = auxData.[AuxDataKey.TwoStringsInt("Vol", ticker, count)]
This works, but I find it quite cumbersome.
One alternative would be to create another DU:
type StringInt = String of string | Int of int
and then have the Map keys be lists of such objects. There would be no need to crate a DU for the Map keys and the StringInt DU is much simpler. On the other hand, this alternative looks less safe as the compiler could accept lists, for example, in which the first element is an Int and the second is a String, which would not fit any of the cases in the AuxDataKey DU. I have not tried this in practice, as there may be better alternatives.
Is there an idiomatic way to deal with objects that must be of the same type but have different shapes?