Как уже указывалось, это сложная проблема, потому что кортеж не является единственным типом - это семейство типов, таких как 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 (который является динамическим, поэтому он не должен иметь дело с безопасностью статического типа).