Search code examples
functional-programmingf#currying

Passing the same chain of parameters multiple times with currying


Given this expression:

// val fn1 : a:'a -> b:'b -> c:'c -> d:'d -> e:'e -> f:'f -> g:'g -> unit
// val fn2 : a:'a -> b:'b -> c:'c -> d:'d -> e:'e -> f:'f -> g:'g -> unit

type T =
  | A
  | B

// val t : T
// val a : 'a
// val b : 'b
// val c : 'c
// val d : 'd
// val e : 'e
// val f : 'f
// val g : 'g

match t with
| A -> fn1 a b c d e f g
| B -> fn2 a b c d e f g

Is there a way to not repeat the same chain of parameters while calling a function that supports currying? so you could write some weird stuff like this

(a, b, c, d, e, f, g)
|||||||> (match t with A -> fn1 | B -> fn2)

Would this be a case for an anonymous record? What are the common practices to achieve this?


Solution

  • Just apply, rather than pipes?

    (match t with
    | A -> curried1
    | B -> curried2
    ) 1 2 3 4
    

    FSharp closures are implemented as FSharpFunc<T, TResult>, which have an invoke method which let you call the method without multiple partial applications.

    I wouldn't recommend going that way, but in extreme cases you can use reflection to invoke a function with an array of parameters.

    let funInvoke fn args =
            let fnType = fn.GetType()
            if not (FSharpType.IsFunction fnType) then
                failwith "Not a function"
    
            let invoke = Array.head (fnType.GetMethods())
            invoke.Invoke(fn, args)
    

    and then

    funInvoke curried1 [|1; 2; 3 ; 4 |]