在 Python 中,你可以这样写:
def add(a, b, c):
return a + b + c
list_of_args = [4, 5, 6]
print(add(*list_of_args))
前面的星号list_of_args
扩展了可迭代对象,使其元素是参数 a、b 和 c 的值。
你能在 F# 中做类似的事情吗?具体来说,我正在寻找一个好的或惯用的 F# 解决方案,并且不想乱用反射等等。
在 Python 中,你可以这样写:
def add(a, b, c):
return a + b + c
list_of_args = [4, 5, 6]
print(add(*list_of_args))
前面的星号list_of_args
扩展了可迭代对象,使其元素是参数 a、b 和 c 的值。
你能在 F# 中做类似的事情吗?具体来说,我正在寻找一个好的或惯用的 F# 解决方案,并且不想乱用反射等等。
你可以这样做:
type T =
static member func([<ParamArray>] args: 'T[]) = printfn "%A" args
T.func(1, 2, 3)
let args = [|1; 2; 3|]
T.func(args)
两者都调用 print [|1; 2; 3|]
。
F# 没有开箱即用的东西——主要是因为 F# 是静态类型语言,因此很难支持类似的模式(列表可能只包含一种类型的值,而函数可能有不同的参数)。
如链接答案中所述,您可以使用反射来模拟类似的想法,这将是缓慢且不安全的,但如果您有充分的理由这样做,您可以尝试一下。
使用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#,我会尽量避免它,但它可能会奏效。
在这里了解您的意图会很有趣。如果您只需要一种将特定函数的参数视为一等值的方法,则可以简单地定义该函数以将值元组作为其单个参数:
let f (a, b, c) = a + b + c
let args = (1, 2, 3)
let result = f args
对于方法,这实际上是“默认样式”。唯一的缺点:您不能真正将部分应用程序与此类功能/方法一起使用。