Search code examples
scalafunction-composition

Composing functions with multiple arguments


How can I compose a function where apply takes more than one argument?

Here is a contrived example:

val sum: List[Int] => Int = l => l.sum

val double: Int => Int = i => i * i

double.compose(sum).apply(List(1,2,3)) //=> 36

val sumAppend: (List[Int], Int) => Int = (l, i) => i :: l sum

double.compose(sumAppend).apply(List(1,2,3), 1) // Attempt to append 1 to list then sum

The above give me a typed inferred error?


Solution

  • Define compose2, for instance as an extension method for Function1:

    implicit class ComposeFunction2[A, B, C, D](f1: Function1[C, D]) {
      def compose2(f2: Function2[A, B, C]): Function2[A, B, D] =
        (a: A, b: B) => f1(f2(a, b))
    }
    

    This will be faster than the alternatives as it does not allocate tuples. Usage:

    scala> val double: Int => Int = i => i * i
    double: Int => Int = <function1>
    
    scala> val sumAppend: (List[Int], Int) => Int = (l, i) => i :: l sum
    sumAppend: (List[Int], Int) => Int = <function2>
    
    scala> double.compose2(sumAppend).apply(List(1,2,3), 1)
    res5: Int = 49