在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#解决方案,并且不想用反射等来解决问题。
答案 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
对于方法,这实际上是“默认样式”。 唯一的缺点:您无法真正使用具有此类函数/方法的部分应用程序。