David Weber
David Weber

Reputation: 1995

Define and invoke partially applied function with varargs?

There is something odd about partially applying a curried function with varargs. Consider this example:

def adder(a: Int)(b: Int*) = b.map(_ + a) 

adder(1)(1,2,3,4)     // res1: Seq[Int] = ArrayBuffer(2, 3, 4, 5)
val add2 = adder(2) _ // add2: Seq[Int] => Seq[Int]
add2(1,2,3,4)         // Fails to compile
add2(Seq(1,2,3,4)     // res3: Seq[Int] = List(3, 4, 5, 6)

While I am aware of a previous question, I would still like to know why the compiler does this and if there is some clever solution in these cases.

Upvotes: 1

Views: 93

Answers (1)

Kolmar
Kolmar

Reputation: 14224

This is because methods and functions are different things in Scala. Methods support type parameters, default and named arguments, varargs, implicit argument lists, etc.

When you do eta expansion method _, the method is converted to a function which is simply an instance of a Function0 to Function22 trait, and doesn't support any of those features.

You can express function types with a shorthand Int => String, or (A, B) => R. Methods on the other hand have non-value types, and there is no general way to reference such a type in a Scala program.

If you want to have a callable variable, that supports varargs, or any other method features, you can return an object with an appropriate apply method:

case class adder(a: Int) {
  def apply(b: Int*) = b.map(_ + a)
}

Now it works:

scala> adder(1)(1,2,3,4)
res1: Seq[Int] = ArrayBuffer(2, 3, 4, 5)

scala> val add2 = adder(2)
add2: adder = adder(2)

scala> add2(1,2,3,4)
res2: Seq[Int] = ArrayBuffer(3, 4, 5, 6)

Upvotes: 2

Related Questions