如何在F#List和F#Tuple之间进行转换?

kev*_*kev 18 f#

有没有办法在F#List和F#Tuple之间进行转换?

例如:

[1;2;3] -> (1,2,3)    
(1,2,3,4) -> [1;2;3;4]
Run Code Online (Sandbox Code Playgroud)

我需要两个函数来做到这一点:

let listToTuple list = ...
let tupleToList tuple = ...
Run Code Online (Sandbox Code Playgroud)

先感谢您.

Huu*_*som 19

除了listToTuple,那么pblasucci有正确的答案.但是你不会对结果感到满意,除非你对所涉及的类型类型有所了解,或者如果你不想进行大量的装箱和拆箱.

let tupleToList t = 
    if Microsoft.FSharp.Reflection.FSharpType.IsTuple(t.GetType()) 
        then Some (Microsoft.FSharp.Reflection.FSharpValue.GetTupleFields t |> Array.toList)
        else None

let listToTuple l =
    let l' = List.toArray l
    let types = l' |> Array.map (fun o -> o.GetType())
    let tupleType = Microsoft.FSharp.Reflection.FSharpType.MakeTupleType types
    Microsoft.FSharp.Reflection.FSharpValue.MakeTuple (l' , tupleType)
Run Code Online (Sandbox Code Playgroud)


Tom*_*cek 14

正如已经指出的那样,这是一个棘手的问题,因为元组不是单一类型 - 它是一个类型的系列,如int * int * intor 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]
Run Code Online (Sandbox Code Playgroud)

然后你可以组合函数tlte创建一个类型安全的函数,将包含4个元素的嵌套元组转换为如下列表:

let l = (1, (2, (3, 4))) |> (tl (tl (tl te)))
Run Code Online (Sandbox Code Playgroud)

类似地,您可以创建将列表转换为元组的函数 - 请注意,如果列表与预期格式不匹配,这可能会引发异常:

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))
Run Code Online (Sandbox Code Playgroud)

我想这可能与类型安全和可重用函数一样,可以在元组和列表之间进行转换.这根本不是完美的,但这是因为你试图实现一个很少使用的操作.在F#中,元组和列表之间的区别比Python中更明显(Python是动态的,因此它不必处理静态类型安全性).