问题
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?
回答1:
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
回答2:
in this case you can compose only functions that takes single argument. so sumAppend has to be function that takes a single argument of any type and must return a result of Int (i.e. _ => Int
).
you can convert a Function that takes two arguments to a curried function and partially apply the function as shown below.
scala> val sumAppend = (l: List[Int], i: Int) => (i :: l).sum
sumAppend: (List[Int], Int) => Int = $$Lambda$1630/1910012982@44511a58
scala> double.compose(sumAppend.curried.apply(List(1,2,3))).apply(10)
res18: Int = 256
One other option would be to have sumAppend take a single argument which is Tuple of List[Int] and Int.
scala> val sumAppend: ((List[Int], Int)) => Int = l => (l._2 :: l._1).sum
sumAppend: ((List[Int], Int)) => Int = $$Lambda$1597/1903597138@5fa9d195
scala> val x = double.compose(sumAppend).apply((List(1,2,3),10))
x: Int = 256
来源:https://stackoverflow.com/questions/44180861/composing-functions-with-multiple-arguments