3

In Python, you can write this:

def add(a, b, c):
    return a + b + c

list_of_args = [4, 5, 6]
print(add(*list_of_args))

The asterisk in front of list_of_args expands the iterable so that its elements are the values of the parameters a, b and c.

Can you do something similar in F#? Specifically, I'm looking for a good or idiomatic F# solution and do not want to muck around with reflection and so on.

3
  • Possible duplicate: stackoverflow.com/questions/2920094/… Commented Jan 25, 2013 at 9:12
  • I understand what you're asking but what's the use case for code of this sort? I mean I can see passing a list as a parameter and I can see functions with variadic argument lists but I'm not quite following where you'd want to use code like this. Commented Jan 25, 2013 at 18:22
  • I'm gluing together together two api:s that deal with 3d vectors differently. One likes to represent them as a three item list and the other has three parameters x, y and z on all functions that uses vectors. Commented Feb 3, 2013 at 0:44

3 Answers 3

5

You could do this:

type T =
  static member func([<ParamArray>] args: 'T[]) = printfn "%A" args

T.func(1, 2, 3)

let args = [|1; 2; 3|]
T.func(args)

Both calls print [|1; 2; 3|].

Sign up to request clarification or add additional context in comments.

Comments

2

F# does not have anything like this out of the box - mainly because F# is statically typed language and so supporting similar patters is difficult (list may only contain values of one type, while function may have different parameters).

As mentioned in the linked answer, you can emulate similar idea using reflection, which is going to be slow and unsafe, but if you have really good reason for doing this, you might give it a try.

Using the tupleToList function from the previous answer and a few active patterns, you can write:

// Converts any F# tuple to a list of objects using reflection
let tupleToList t = 
    if Microsoft.FSharp.Reflection.FSharpType.IsTuple(t.GetType()) 
        then Some (Microsoft.FSharp.Reflection.FSharpValue.GetTupleFields t |> Array.toList)
        else None

// Active pattern that accepts any object and extracts its members
// if it is a tuple or a sequence of values (e.g. list)
let (|Arguments|_|) (a:obj) = 
  match a, tupleToList a with
  | _, Some t -> Some t
  | :? System.Collections.IEnumerable as l, _ -> 
      l |> Seq.cast |> List.ofSeq |> Some
  | _ -> None

// Treat the argument as an int (this may fail)
let (|Int|_|) (a:obj) = match a with :? int as n -> Some n | _ -> None

// Function that assumes to get three integers
let f (Arguments [Int a;Int b;Int c]) = 
  printfn "%d" (a + b + c)

f (1, 2, 3) // Call with tuple
f [1;2;3]   // Call with a list
f (1, "hi", 3, 141.1)  // This will fail at runtime, but compiler allows it :-(

This is probably not very idiomatic F# and I would try to avoid it, but it might do the trick.

3 Comments

Thanks. I suppose the anser is "can't be done" without reflection?
I think the answer by @Daniel is a good alternative (wtihout reflection) if you're happy to use static methods instead of plain functions.
"mainly because F# is statically typed language and so supporting similar patters is difficult" C++ is a statically typed language but can handle this effortlessly. ;-]
1

It would be interesting to know your intention here. If you just need a way to treat the arguments of a specific function as a first-class value, you can simply define the function to take a tuple of values as its single argument:

let f (a, b, c) = a + b + c
let args = (1, 2, 3)
let result = f args

For methods, this is actually the "default style". The only drawback: You cannot really use partial application with such functions/methods.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.