处理相同类型但不同形状的物体的惯用方法是什么?

Sol*_*lma 3 f# dictionary 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>
Run Code Online (Sandbox Code Playgroud)

可以通过以下方式创建密钥:

let key = AuxDataKey.TwoStringsInt("Vol", ticker, count)
Run Code Online (Sandbox Code Playgroud)

并且可以从即时创建的密钥中检索信息:

let vols = auxData.[AuxDataKey.TwoStringsInt("Vol", ticker, count)]
Run Code Online (Sandbox Code Playgroud)

这有效,但我发现它非常麻烦.

另一种方法是创建另一个DU:

type StringInt = String of string | Int of int
Run Code Online (Sandbox Code Playgroud)

然后让Map键成为这些对象的列表.没有必要为地图键创建DU,StringIntDU更简单.另一方面,这种替代方案看起来不太安全,因为编译器可以接受列表,例如,第一个元素是Int,第二个是String,它不适合AuxDataKeyDU 中的任何情况.我没有在实践中尝试过,因为可能有更好的选择.

是否有惯用的方法来处理must相同类型但具有不同形状的对象?

The*_*Fox 5

你这样做的方式非常惯用.请注意,AuxDataKey在引用DU情况时,您不需要为类型名称添加前缀,因此您只需编写:

let key = TwoStringsInt("Vol", ticker, count)
Run Code Online (Sandbox Code Playgroud)

有可能将您的类型分解为有意义的部分,但在不知道组件部分的真正含义的情况下很难分辨.这可以摆脱一些重复.例如,只需拉出其中一个字符串,所有情况都有共同点就可以了:

type SubKey =
    | A of string
    | B of int
    | C of string * int
    | D of int * int
    | E of string * int * int

type AuxDataKey =
    { Key : string
      SubKey : SubKey }
Run Code Online (Sandbox Code Playgroud)

其他一些语言具有这样的功能,其中联合案例由类型系统根据返回的不同值自动推断.我相信TypeScript可以做到这一点,而OCaml与其多态变体有类似之处.但是,F#在这方面完全名义上是键入的,这意味着必须在使用之前定义和命名每个DU案例.