Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does this partial application not compile?

Tags:

scala

The following:

val add = (a: Int, b: Int) => a + b 

gets converted to:

object add extends Function2[Int, Int, Int] {
  def apply(a: Int, b: Int) = a + b
}

while

val a1 = add(_: Int, 3)

gets converted to:

object a1 extends Function1[Int, Int] {
  def apply(x: Int): Int = {
    add(x, 3)
  }
}

But when I do:

scala> val a2 = add _
a2: () => (Int, Int) => Int = <function0>

And then call a2, it throws an error:

scala> a2(1, 2) 
<console>:11: error: too many arguments for method apply: ()(Int, Int) => Int in trait Function0
              a2(1, 2)
                ^

Why is this? Why does the following work?

a2()(1, 2)
like image 467
Tyrion Lannister Avatar asked May 16 '15 16:05

Tyrion Lannister


1 Answers

add is already a Function2[Int, Int, Int]. If you want a2 to have the same type, then a simple assignment will suffice.

scala> val a2 = add
a2: (Int, Int) => Int = <function2>

scala> a2(1, 2)
res3: Int = 3

What you're thinking of is eta-expansion of a method into a function. If we had:

def add(a: Int, b: Int): Int = a + b

Then, we would use add _ to get the eta-expansion to assign to a value.

scala> def a2 = add _
a2: (Int, Int) => Int

scala> a2(1, 2)
res4: Int = 3

But add is already a function, so the underscore has a different meaning. add is now a value and not a method. Since add is a value, it is like a parameter-less method that returns a Function2[Int, Int, Int]. And if we try to get the eta-expansion of that, we get () => Function2[Int, Int, Int].

Consider a simpler example where we have a simple val a = 1. a is essentially the same as a parameter-less method that returns 1 (def a = 1). If I try to obtain the eta-expansion, I will get () => Int.

scala> val a = 1
a: Int = 1

scala> val a2 = a _
a2: () => Int = <function0>
like image 99
Michael Zajac Avatar answered Nov 01 '22 14:11

Michael Zajac