In F#, how do you curry a function that accepts a variable number of parameters?
I have code like this...(the log function is just an example, the exact implementation doesn't matter)
let log (msg : string) =
printfn "%s" msg
log "Sample"
It gets called throughout the code with sprintf formatted strings, ex.
log (sprintf "Test %s took %d seconds" "foo" 2.345)
I want to curry the sprintf functionality in the log function so it looks like...
logger "Test %s took %d seconds" "foo" 2.345
I've tried something like
let logger fmt ([<ParamArray>] args) =
log (sprintf fmt args)
but I cannot figure out how to pass the ParamArray argument through to the sprintf call.
How is this done in F#?
let log (s : string) = ()
let logger fmt = Printf.kprintf log fmt
logger "%d %s" 10 "123"
logger "%d %s %b" 10 "123" true
The behaviour of printf
-like functions in F# is in some way special. They take a format string, which specifies what the expected arguments are. You can use Printf.kprintf
as shown by desco to define your own function that takes a format string, but you cannot change the handling of format strings.
If you want to do something like C# params
(where the number of arguments is variable, but does not depend on the format string), then you can use ParamArray
attribute directly on a member:
open System
type Foo =
static member Bar([<ParamArray>] arr:obj[]) =
arr |> Seq.mapi (fun i v -> printfn "[%d]: %A" i v)
Then you can call Foo.Bar
with any number of arguments without format string:
Foo.Bar("hello", 1, 3.14)
This is less elegant for string formatting, but it might be useful in other situations. Unfortunatelly, it will only work with members (and not with functions defined with let
)