F#Concat两个元组不解构

时间:2018-11-26 15:44:47

标签: f# tuples

我有两个长度未知的元组,我想将它们加在一起形成第三个元组。

例如:

// given two tuples
let tuple1 = (1, 2)
let tuple2 = (3, 4, 5)

// resulting in
let tuple3 = (1, 2, 3, 4, 5)

我想出的解决方案是先解构两个元组,然后再创建一个新的元组,如下所示:

let a b = tuple1
let c d e = tuple2
let tuple4 = (a, b, c, d, e)

但是,这不适用于长度未知的元组。

另一个解决方案可能是:

let tuple5 = tuple1, tuple2

但这会导致两个元组如下所示:

(int * int) * (int * int * int)

我缺少一个元组函数吗?我还有什么要注意的吗?谢谢。

3 个答案:

答案 0 :(得分:2)

F#元组的设计意味着您需要编写知道元组长度的代码-不同长度的元组具有不同的类型,并且您不能编写在元组的长度上通用的代码。

如果您想要一个允许存储任意数量的值并将其连接的数据结构,则最好使用列表,该列表允许使用@运算符进行连接:

let list1 = [1; 2]
let list2 = [3; 4; 5]

let list3 = list1 @ list2

需要注意的是,列表只能存储一种类型的值-例如您的示例中的int。如果您需要存储任意数量的任意事物,则可能需要一个已区分联合的列表。

答案 1 :(得分:2)

解释是,元组不打算用作列表(长度可能未知)。可以将元组视为非常简单的结构或类,其中成员被隐式命名为“第一”,“第二”,“第三”等。因此,您的问题就像回答“如何连接两个结构的成员”?答案可能是反思,但最有可能在为程序的数据类型建模时暗示一些问题。

元组的典型用例是非常简单的临时数据类型,或者其他情况下成员的长度和顺序很自然。例如:

type Point2D = float * float
type Point3D = float * float * float
type Size = int * int
type Error = int * string

答案 2 :(得分:0)

这不是一个答案,因为它仅演示了尝试为元组使用F#类型系统是徒劳的。但是从技术上讲,确实可以将各种长度的元组与通用函数组合在一起,这可以以类型安全的方式使用其参数。 ,,它将拥有一个未指定的返回类型,需要注释。这是通过采用两个功能而实现的,这些功能正确地在函数式编程中并不占优势:

还有其他一些限制:我们无法对1元组进行编码,这种重载无法唯一地解决,因为它可能又代表n元组。类似的原因也排除了使用两个长度不同的元组作为静态成员的直接参数。

type X = X with
    static member ($) (_ : X, (a, b)) = [|box a; box b|]
    static member ($) (_ : X, (a, b, c)) = [|box a; box b; box c|]
let inline t2a x = X $ x

open Microsoft.FSharp.Reflection
let a2t arg : 'r =
    FSharpValue.MakeTuple(arg, typeof<'r>) :?> 'r

let inline (@@) a b =
    Array.append (t2a a) (t2a b) |> a2t

let (t : int * char * int64 * string) = (1, 'b') @@ (3L, "d")
// val t : int * char * int64 * string = (1, 'b', 3L, "d")
let (u : int * int * int * int * int) = (1, 2, 3) @@ (4, 5)
// val u : int * int * int * int * int = (1, 2, 3, 4, 5)

鉴于上述情况,将4元组与2元组连接起来会产生编译时错误。

let (v : int * int * int * int * int * int) = (1, 2, 3, 4) @@ (5, 6)
// error FS0001: No overloads match for method 'op_Dollar'.