Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F# - splat/unpacking argument lists

Tags:

f#

Has F# built-in operator/function that allow unpack argument list/tuple and pass it to function call?

Example usage:

// simple add function
let add (a1 : int) (a2 : int) (a3 : int) = a1 + a2 + a3

// what I want to achieve
let result = add (missing_operator)[1; 2; 3]

// or
let result' = add (missing_operator) (1, 2, 3)

// flattening list
let a = [1; 2; 3]
let b = [(missing_operator) a; 4; 5]

Similiar to Python * operator

def add(a1, a2, a3):
   return a1 + a2 + a3

add(*[1,2,3])

Or apply(func_name, args_list) function

apply(add, [1, 2, 3])
like image 290
Lukasz Szozda Avatar asked Aug 21 '15 10:08

Lukasz Szozda


2 Answers

For pairs and triads there are predefined operators ||>, <||, |||> and <||| analogous to |> and <| for a single argument (monuple):

let add a b c = a + b + c

add <||| (1, 2, 3)
(1, 2, 3) |||> add

You could add such operators yourself:

let (||||>) (a1, a2, a3, a4) func = func a1 a2 a3 a4

let foo u v x y = ( u + v ) * ( x + y )
(1, 2, 3, 4) ||||> foo

All these operators also work for non-uniform types.

If you want to give up type-safety, the following works (for non-null arguments):

let invokeWith args op =
    let func = op.GetType().GetMethod("Invoke", args |> Array.map(fun a -> a.GetType()))
    func.Invoke(op, args)

add |> invokeWith [|1; 2; 3|]

which also works for non-uniform argument types:

let pad (a : string) l = a.PadRight(l)
pad |> invokeWith [| "a"; 12 |]

Of course, once you give up static type checks, you're on your own:

// compiles but throws at runtime
pad |> invokeWith [| "a"; None |]

whereas

// does not compile
// ( "a", None ) ||> pad
like image 163
CaringDev Avatar answered Oct 27 '22 01:10

CaringDev


I think one of idiomatic ways to do so in F# could be something like this:

  // simple add function
  let add (a1 : int) (a2 : int) (a3 : int) = a1 + a2 + a3

  // what I want to achieve
  let result = match [1; 2; 3] with | [a;b;c] -> add a b c // pattern matching works on lists

  // or
  let result' = let (a,b,c) = (1, 2, 3) in add a b c // unpacking tuples

  // flattening list
  let a = [1; 2; 3]
  let b =                            // sequence expressions with yield!
    seq {
        yield! a
        yield 4
        yield 5
      } |> Seq.toList

  let c = [4; 5]
  let b' = 
    seq {
        yield! a
        yield! c
      } |> Seq.toList
like image 45
V.B. Avatar answered Oct 27 '22 00:10

V.B.