FSharp检查是否为元组类型

时间:2020-03-03 15:46:43

标签: f#

我想以一种特定的方式格式化一个元组,我试图通过检查该元组的类型(2个元素,3个元素等)来做到这一点。我在第三行收到一条错误消息:

This runtime coercion of type test from type
'd
to
  'a * ('b * 'c)
involves an indeterminate type based on the information prior to this program point. 
Runtime type tests are not allowed on some type. Further type annotations are needed.

这是我的尝试:

  let namer x =
    match x with
    | :? ('a * ('b * 'c)) as a, b, c -> sprintf "%s_%s_%s" (a.ToString()) (b.ToString()) (c.ToString())
    | :? ('a * 'b) as a, b -> sprintf "%s_%s" (a.ToString()) (b.ToString())
    | a -> sprintf "%s" (a.ToString())

您应该如何做这样的事情?我希望能够根据元组的类型来格式化字符串。

我最终想要的是能够将嵌套的元组“展平”为字符串,而无需加上括号。例如:

// What I want
let x = (1, (2, (3, 4)))
let name = namer x
printfn "%s" name
> 1_2_3_4

更新:这与“如何在F#列表和F#元组之间转换?”问题不同。找到here。我知道该怎么做。我想要的是能够检测我是否有一个元组以及什么类型的元组。理想的情况是可以使用单个元素,元组或嵌套2个元素元组的通用函数。例如,法律依据为:

let name = namer 1
// or
let name = namer (1, 2)
// or 
let name = namer (1, (2, 3))
// or
let name = namer (1, (2, (3, 4)))

我也想处理非整数值。例如:

let name = namer (1, ("2", (3, "chicken")))

1 个答案:

答案 0 :(得分:2)

您可以通过一些反射和递归函数来实现:

let isTuple tuple =
    tuple.GetType() |> Reflection.FSharpType.IsTuple 

let getFields (tuple: obj) = 
    tuple |> Reflection.FSharpValue.GetTupleFields |> Array.toList

let rec flatten fields =
    fields
    |> List.collect(
        fun tuple ->
            if isTuple tuple
            then flatten (getFields tuple)
            else [tuple]
    )

let namer(tuple: obj) = 
    if isTuple tuple
    then tuple |> getFields |> flatten
    else [tuple]

namer(1, "test") |> printfn "%A"
namer(1, ("2", (3, "chicken"))) |> printfn "%A"

灵感来自: