将列表作为位置参数传递给F#中的Python函数

时间:2013-01-25 08:51:19

标签: f# iterable function-parameter

在Python中,你可以这样写:

def add(a, b, c):
    return a + b + c

list_of_args = [4, 5, 6]
print(add(*list_of_args))

list_of_args前面的星号展开了iterable,使其元素是参数a,b和c的值。

你能在F#做类似的事吗?具体来说,我正在寻找一个好的或惯用的F#解决方案,并且不想用反射等来解决问题。

3 个答案:

答案 0 :(得分:5)

你可以这样做:

type T =
  static member func([<ParamArray>] args: 'T[]) = printfn "%A" args

T.func(1, 2, 3)

let args = [|1; 2; 3|]
T.func(args)

两次调用都打印[|1; 2; 3|]

答案 1 :(得分:2)

F#没有开箱即用的东西 - 主要是因为F#是静态类型的语言,所以支持类似的模式很困难(列表可能只包含一种类型的值,而函数可能有不同的参数)。

正如linked answer中所提到的,你可以使用反射来模仿类似的想法,这将是缓慢且不安全的,但如果你有充分的理由这样做,你可以尝试一下。

使用上一个答案中的tupleToList函数和一些活动模式,您可以写:

// Converts any F# tuple to a list of objects using reflection
let tupleToList t = 
    if Microsoft.FSharp.Reflection.FSharpType.IsTuple(t.GetType()) 
        then Some (Microsoft.FSharp.Reflection.FSharpValue.GetTupleFields t |> Array.toList)
        else None

// Active pattern that accepts any object and extracts its members
// if it is a tuple or a sequence of values (e.g. list)
let (|Arguments|_|) (a:obj) = 
  match a, tupleToList a with
  | _, Some t -> Some t
  | :? System.Collections.IEnumerable as l, _ -> 
      l |> Seq.cast |> List.ofSeq |> Some
  | _ -> None

// Treat the argument as an int (this may fail)
let (|Int|_|) (a:obj) = match a with :? int as n -> Some n | _ -> None

// Function that assumes to get three integers
let f (Arguments [Int a;Int b;Int c]) = 
  printfn "%d" (a + b + c)

f (1, 2, 3) // Call with tuple
f [1;2;3]   // Call with a list
f (1, "hi", 3, 141.1)  // This will fail at runtime, but compiler allows it :-(

这可能不是非常惯用的F#,我会尽量避免它,但它可能会成功。

答案 2 :(得分:1)

在这里了解你的意图会很有趣。如果您只需要一种方法将特定函数的参数视为第一类值,则可以简单地定义函数以将值元组作为其单个参数:

let f (a, b, c) = a + b + c
let args = (1, 2, 3)
let result = f args

对于方法,这实际上是“默认样式”。 唯一的缺点:您无法真正使用具有此类函数/方法的部分应用程序。