Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write a variadic function in F# emulating a similar Haskell solution?

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.

like image 345
robkuz Avatar asked Jan 30 '15 20:01

robkuz


People also ask

Which of the functions are variadic?

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, ...);.

How do you pass a Vararg to a function?

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.

What is variadic function in Python?

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.

How do you declare a variadic function in C++?

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.


1 Answers

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.

like image 111
Gus Avatar answered Nov 09 '22 23:11

Gus