Howto write a function taking variable number of arguments in F#

c# f#


I've got a function in C#, and I'd like to port it (among some other stuff) over to F#, just for the sake of doing it. Unfortunately, I just hit a case for which there seems to be no way to express this in F#: Take this C# function

public static T Min<T>(params T[] p) where T : IComparable
    T m1 = p[0];

    foreach (T v in p)
        m1 = (m1.CompareTo(v) < 0) ? m1 : v;

    return m1;

I'd thought this would be pretty easy, but I don't understand how I would specify a variable argument list in F#. I have tried this:

let rec Min l =
    match l with
    | [] -> 0 // should throw exception here
    | [v] -> v
    | (h::t) -> min h (Min t)

but calling that from C# expects a Microsoft.FSharp.Collections.List. Is it possible to get it expect a params T[], and if so, how?

1/31/2015 1:02:02 AM

Accepted Answer

A params array is simply an array with an attribute, as Jon notes. Add the attribute before the parameter.

let test ([<ParamArray>] arr : 'a array) = 
    if arr.Length = 0 then invalid_arg "arr"
    // ....

You don't need to specify the type:

let test ([<ParamArray>] arr) = ... // lets type inference do its thing

But... pattern matching doesn't work on the array type. You could write an active pattern to help. Basically, you have to decide what's more important: the F# code or the C# code. The same tradeoff will apply as you design higher order functions, use tuples, use discriminated unions, etc. C# can't express most things, and F# doesn't currently support some of the little bits of sugar C# has (Expression Tree writing in the compiler, for example).

1/31/2015 1:02:17 AM

Are you wanting to call this method from F# or C#? This hubFS post seems to indicate that F# doesn't support parameter arrays on the calling side, but I suspect if you use a normal type annotation for the parameter to make it an array, and also decorate it with ParamArrayAttribute, you should be able to call it with variable arguments from C#.

Can't say I've seen how to decorate a parameter with attributes in F# yet, but I can hunt around if you want... This blog post gives a couple of examples, but not at the parameter level.

Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow