Reputation: 51
I am having trouble understanding why I am unable to use a composed function and compose a new one. For eg: I have two functions f
and g
and I create a composed function composed1
from these. I tried to combine composed with fourth function lastOne
and it fails.
I want to make two composed functions and for the second one Is there a way I can reuse the first composed function?
scala> def f(x: Int)(y: Int) = {
| x + y
| }
f: (x: Int)(y: Int)Int
scala> def g(a: Int)(b: Int) = {
| a + b
| }
g: (a: Int)(b: Int)Int
scala> def composed1(a: Int, b: Int) = {
| f(a) _ andThen g(b)
| }
composed1: (a: Int, b: Int)Int => Int
scala> composed1(2, 2)(5)
res1: Int = 9
scala> def lastOne(l: Int)(x: Int) = {
| l + x
| }
lastOne: (l: Int)(x: Int)Int
scala> def composed2(a: Int, b: Int, c: Int) = {
| composed1(a, b) _ andThen lastOne(c)
| }
<console>:14: error: _ must follow method; cannot follow Int => Int
composed1(a, b) _ andThen lastOne(c)
^
<console>:14: error: missing argument list for method lastOne
Unapplied methods are only converted to functions when a function type is expected.
You can make this conversion explicit by writing `lastOne _` or `lastOne(_)(_)` instead of `lastOne`.
composed1(a, b) _ andThen lastOne(c)
When I use all of them together it works
scala> def test(x: Int, y: Int, z: Int) = {
| f(x) _ andThen g(y) _ andThen lastOne(z)
| }
test: (x: Int, y: Int, z: Int)Int => Int
scala> test(2, 2, 4)(5)
res9: Int = 13
Upvotes: 0
Views: 122
Reputation: 51271
f()()
and g()()
, as you define them, are methods. Methods are not functions but methods can be promoted to functions via "eta expansion". One way to do that is using the underscore in place of a passed parameter.
andThen()
is a method on the Function
trait that takes a function as an argument and returns a new function. It looks as if you can also use a method as the passed argument but it is silently being promoted to Function
status.
So composed1()
looks like a method but it is actually a Function
, because that's what andThen()
returns, and you can't apply the underscore eta expansion to a Function
. It only works on methods.
As an experiment, turn f()()
into a Function
that does the same thing...
def f :Int => Int => Int = (x: Int) => (y: Int) => x + y
...now composed1()
won't compile.
So, now that we know that composed1()
is a Function
, how do we get what we want from composed2()
? Simple. Skip the underscore.
def composed2(a: Int, b: Int, c: Int) =
composed1(a, b) andThen lastOne(c)
composed2(2, 2, 4)(5) //res0: Int = 13
Upvotes: 3