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

How can I (if at all) emulate variable functions (not methods) so that I can write

sum 1 2 3 sum 1 2 3 4 5 sum 1 2 3 4 5 6 7 // etc. 

The code above only means an example - obviously, if I had to list, and then

 [ 1; 2 ; 3] |> List.sum 

is a much better way.

However, I am looking for a structurally similar solution , for example this is a Haskell solution

It is also important that the normal syntax for function calls and parameter values ​​remains unchanged. So

 sum 1 2 3 

against

 sum(1, 2, 3) 

which actually means that

 let sum ([<ParamArray>] arr) = ... 

not required in this particular case.

The motivation for all this: I am studying the external boundaries of the system and syntax such as F #. And I am fully aware that I may have crossed the line of what is already possible.

PS: my specific ideas (which I did not describe here) can also be solved in a completely different way - so I know, and therefore I already did it. So my question is not this: 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.

+7
f # variadic-functions
source share
2 answers

You said that a function, not a method. Therefore, ParamArray not an option.

The Haskell code you linked is based on the output type of the result.

Here you can find a method based on the deduced result type in F #:

 type T = T with static member inline ($) (T, r:'t->'t ) = fun ab -> a + b static member inline ($) (T, r:'t->'t->'t ) = fun abc -> a + b + c static member inline ($) (T, r:'t->'t->'t->'t) = fun abcd -> 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 abc = a * b * c let res2 = mult3Numbers 3 (sum 3 4 ) 10 let res3 = mult3Numbers 3 (sum 3 4 5) 10 

UPDATE

And here is a recursive polyvarian 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>) ix 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 abc = 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 see this multivariate fold .

+18
source share

As pointed out in the comments, you can use the ParamArray attribute in F # and this will allow you to call a function with several parameters - although you will have to use .NET notation and write sum(1,2,3,4,5,6) .

However, I probably would not have done this in practice. If you write a function that accepts input consisting of an unknown number of values, then using a list is likely to be a better design:

 List.sum [1; 2; 3 ] List.sum [1; 2; 3; 4; 5 ] List.sum [1; 2; 3; 4; 5; 6; 7 ] 

These are just a few characters, and it better models the problem you are solving, at least based on the example of toys that you posted here.

It is hard to give a good answer without knowing what the problem is that you are actually solving. But in general, I think getting a list is a good F # default. Using ParamArray is useful in some cases for C # interop.

+5
source share

All Articles