How can I (if at all) emulate variadic functions (not methods) so that I could write
sum 1 2 3
sum 1 2 3 4 5
sum 1 2 3 4 5 6 7
// etc.
The code above is just meant as an example - obviously if I would have to sum up a list then
[ 1; 2 ; 3] |> List.sum
is a much better way.
However I am looking for a structurally similar solution like this Haskell solution
What is also important is that the normal syntax for function calls and parameter values remains the same. So
sum 1 2 3
vs
sum(1, 2, 3)
which effectively means that
let sum ([<ParamArray>] arr) = ...
is not wanted in this specific case.
The motivation for all of this: I am exploring the outer fringes of F#'s type system and syntax. And I am fully aware of that I might have crossed the boundary of what is possible already.
PS: my concrete ideas (which I have not described here) can also be solved completely differently - so I know and so I have done already. Therefore my question is not: how can this be solved differently but how can this be solved structurally like Haskell.
PPS: Double Karma-Points if you can make the whole solution recursive.
Variadic functions are functions (e.g. printf) which take a variable number of arguments. The declaration of a variadic function uses an ellipsis as the last parameter, e.g. int printf(const char* format, ...);.
In Kotlin, You can pass a variable number of arguments to a function by declaring the function with a vararg parameter. a vararg parameter of type T is internally represented as an array of type T ( Array<T> ) inside the function body.
Variadic parameters (Variable Length argument) are Python's solution to that problem. A Variadic Parameter accepts arbitrary arguments and collects them into a data structure without raising an error for unmatched parameters numbers.
Variadic functions are functions (e.g. std::printf) which take a variable number of arguments. To declare a variadic function, an ellipsis appears after the list of parameters, e.g. int printf(const char* format...);, which may be preceded by an optional comma.
You said function, not method. So ParamArray
is not an option.
The Haskell code you linked is based on the inferred result type.
Here's a way to resolve based on the inferred result type in F#:
type T = T with
static member inline ($) (T, r:'t->'t ) = fun a b -> a + b
static member inline ($) (T, r:'t->'t->'t ) = fun a b c -> a + b + c
static member inline ($) (T, r:'t->'t->'t->'t) = fun a b c d -> a + b + c + d
let inline sum (x:'a) :'r = (T $ Unchecked.defaultof<'r>) x
let x:int = sum 2 3
let y:int = sum 2 3 4
let z:int = sum 2 3 4 5
let d:decimal = sum 2M 3M 4M
let mult3Numbers a b c = a * b * c
let res2 = mult3Numbers 3 (sum 3 4 ) 10
let res3 = mult3Numbers 3 (sum 3 4 5) 10
UPDATE
The above code doesn't work anymore as from F# 4.1 (see the comments) but here's a better example with a recursive polyvariadic function taking n (unlimited) arguments:
type T = T with
static member ($) (T, _:int ) = (+)
static member ($) (T, _:decimal) = (+)
let inline sum (i:'a) (x:'a) :'r = (T $ Unchecked.defaultof<'r>) i x
type T with
static member inline ($) (T, _:'t-> 'rest) = fun (a:'t) -> (+) a >> sum
let x:int = sum 2 3
let y:int = sum 2 3 4
let z:int = sum 2 3 4 5
let d:decimal = sum 2M 3M 4M
let mult3Numbers a b c = a * b * c
let res2 = mult3Numbers 3 (sum 3 4) (sum 2 2 3 3)
let res3 = mult3Numbers 3 (sum 3 4 5 11 13 20) 10
You can also have a look at this polyvariadic fold.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With