f# - 是否有一个通用函数可以识别嵌套可区分联合的情况?

标签 f# nested discriminated-union

我创建了一个嵌套的可区分联合 (DU),如下所示:

type OptimizationPeriod = | All
                          | Long
                          | Short

type OptimizationCriterion = | SharpeRatio      of OptimizationPeriod
                             | InformationRatio of OptimizationPeriod
                             | CalmarRatio      of OptimizationPeriod

还有一个非嵌套的 DU:

type Parallelism = Sequential | PSeq

我有一个 JSON 配置文件,其中包含定义 DU 案例的字符串。以下函数设法识别非嵌套 Parallelism DU 的情况:

let stringToDUCase<'t> (name: string) : 't =
        let dUCase =
            Reflection.FSharpType.GetUnionCases( typeof<'t> )
            |> Seq.tryFind (fun uc -> uc.Name = name)
            |> Option.map (fun uc -> Reflection.FSharpValue.MakeUnion( uc, [||] ) :?> 't)
        match dUCase with
        | Some x -> x
        | _ -> let msg = sprintf "config.json - %s is not a case in DU %A" name typeof<'t>
               failwith msg

注意:我当然是从某处复制的,因为这个函数有点让我头疼,向作者道歉,因为我不记得它是从哪里来的。

不幸的是,这个函数无法识别嵌套 DU 的大小写:

stringToDUCase<OptimizationCriterion> config.Trading.Criterion
System.Exception: config.json - SharpeRatio All is not a case in DU FractalTypes.OptimizationCriterion

两个问题:

1) 我能够编写一个函数来处理特定 OptimizationCriterion DU 并且能够识别情况。是否有符合 stringToDUCasegeneric 函数可以做同样的事情?

2) 使用 OptimizationCriterion*OptimizationPeriod 类型的元组而不是嵌套 DU 会更好吗? (我可能不得不调用 stringToDUCase 两次,但这不是问题)

最佳答案

All 这样的“空”DU 案例只是一个值,但是像 SharpeRatio 这样的“非空”DU 案例实际上是一个函数,它有一个值并且返回类型。在这种情况下,SharpeRatio 的类型为 OptimizationPeriod -> OptimizationCriterion

您现有的 stringToDUCase 函数总是将一个空数组传递给 MakeUnion(暗示一个空的 DU 案例)。因此,这是适用于任何 DU 案例的函数的修改版本:

let stringToParamDUCase<'t> (name: string) =
    Reflection.FSharpType.GetUnionCases(typeof<'t>)
    |> Seq.tryFind (fun uc -> uc.Name = name)
    |> Option.map (fun uc ->
        fun (parameters:obj []) -> Reflection.FSharpValue.MakeUnion(uc, parameters) :?> 't)
    |> Option.defaultWith (fun () ->
        failwith (sprintf "config.json - %s is not a case in DU %A" name typeof<'t>))

注意它返回一个函数obj[] -> 't。我还稍微简化了错误处理。

你可能会这样使用它:

let myOptimizationPeriod = stringToParamDUCase<OptimizationPeriod> "All" [||]
let f = stringToParamDUCase<OptimizationCriterion> "SharpeRatio"
let myOptimizationCriterion = f [|All|]

关于f# - 是否有一个通用函数可以识别嵌套可区分联合的情况?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47925643/

相关文章:

f# - 如何使用重载的静态运算符

php - 寻找有关从查询结果构建对象的建议/最佳实践

javascript - 修改对象中的第n个嵌套属性

javascript - 为什么 TypeScript 在使用 .includes 搜索数组中的字符串时会抛出错误?

f# - 匹配有区别的联合案例而不是内容

f# - 如何比较深度嵌套的歧视工会?

f# - 如何在 mono (OS X) 中加载 .fsx 文件,并使用内部类型\函数?

.net - 重复追加到列表直到抛出异常

html - 选择嵌套的 Li 元素

c# - 从 C# 引用异步 F# 数据类型