正如已经指出的那样,这是一个棘手的问题,因为元组不是单一类型 - 它是一族类型,例如
int * int * int
或
int * int
,F# 并没有提供任何以整个类型族作为参数的方法。你可以编写许多类似的函数(非常不便),或者使用反射(速度有点慢且不安全)。
或者,你可以将函数限制为具有某种结构的元组 - 例如,而不是处理
(1, 2, 3, 4)
,你可以使用嵌套的元组,如
(1, (2, (3, 4)))
。这有点不太方便,但它保持了类型安全性,而且并不糟糕。
然后,你可以轻松地编写合子来动态构建转换函数:
// creates function for converting tuple (possibly with a nested
// tuple in the second component to list
let tl f (a, b) = a::(f b)
// converts last element of the tuple to singleton list
let te a = [a]
然后,您可以将函数tl
和te
组合在一起,创建一个类型安全的函数,将包含4个元素的嵌套元组转换为列表,如下所示:
let l = (1, (2, (3, 4))) |> (tl (tl (tl te)))
同样地,你可以创建将列表转换为元组的函数 - 需要注意的是,如果列表与预期格式不符,这可能会引发异常:
let le = function
| [x] -> x
| _ -> failwith "incompatible"
let lt f = function
| [] -> failwith "incompatible"
| x::xs -> (x, f xs)
// convert list to a tuple of four elements
let t = [1; 2; 3; 4] |> lt (lt (lt le))
我想这可能是将元组和列表之间进行类型安全且可重复使用的函数最接近的实现方式。它并不完美(完全不是),但这是因为你试图实现一个非常少用的操作。在 F# 中,元组和列表之间的区别比例如 Python(它是动态的,因此不必处理静态类型安全)更加清晰。