在F#中,你如何理解ParamArray函数(如sprintf)?

时间:2012-06-21 19:47:51

标签: f# printf currying paramarray

在F#中,你如何理解接受可变数量参数的函数?

我有这样的代码......(日志功能只是一个例子,确切的实现并不重要)

let log (msg : string) =
    printfn "%s" msg

log "Sample"

在整个代码中使用sprintf格式化字符串调用它,例如

log (sprintf "Test %s took %d seconds" "foo" 2.345)

我想在日志功能中讨论sprintf功能,看起来像......

logger "Test %s took %d seconds" "foo" 2.345

我尝试过像

这样的东西
let logger fmt ([<ParamArray>] args) =
    log (sprintf fmt args)

但我无法弄清楚如何将ParamArray参数传递给sprintf调用。

如何在F#中完成?

2 个答案:

答案 0 :(得分:7)

let log (s : string) = ()
let logger fmt = Printf.kprintf log fmt

logger "%d %s" 10 "123"
logger "%d %s %b" 10 "123" true

答案 1 :(得分:6)

printf的行为 - 就像F#中的函数一样,在某种程度上是特殊的。它们采用格式字符串,指定预期参数是什么。您可以使用desco所示的Printf.kprintf来定义您自己的带有格式字符串的函数,但不能更改格式字符串的处理。

如果你想做一些像C#params(其中参数的数量是可变的,但不依赖于格式字符串),那么你可以直接在成员上使用ParamArray属性:

open System

type Foo = 
  static member Bar([<ParamArray>] arr:obj[]) =
    arr |> Seq.mapi (fun i v -> printfn "[%d]: %A" i v)

然后你可以使用任意数量的参数调用Foo.Bar而不使用格式字符串:

Foo.Bar("hello", 1, 3.14)

这对字符串格式不太优雅,但在其他情况下可能很有用。不幸的是,它只适用于成员(而不是使用let定义的函数)