I am learning Scala and was experimenting in the command line. I am not able to understand why the second line fails to compile. Can someone please explain.
val list = List(1,2,3,4)
list.map(_+1) //This works. List(2,3,4,5)
list.map(List(_+1)) //But, Compilation Fails here
list.map(x=>List(x+1)) //This works. List(List(2),List(3),List(4),List(5))
Thank you.
Scala will expand _ (when used in a placeholder position) to x => x, except when such expansion would result in the identity function (more on that at the end of this answer):
list.map(_+1) // same as list.map(x => x + 1) (1)
list.map(List(_+1)) // same as list.map(List(x => x+1)) (2)
In the case of (1), scala can infer that x has type Int (since list: List[Int]).
However (2) fails with
error: missing parameter type for expanded function ((x$1) => x$1.$plus(1))
because scala can't infer x's type in List(x => x+1).
About the expansion and identity function:
scala> list.map(List(_))
res3: List[List[Int]] = List(List(1), List(2), List(3), List(4))
works, because the list.map(List(x => x)) expansion is rejected, and the next possible one is list.map(x => List(x)), which gives res3.
The type of list is List[Int]. So, the argument to list.map(...) has to be a function from Int to something.
What it seems you are trying to create with List(_+1) is a list of functions from integers to integers that happen to have one element: the successor function.
It fails to compile because this is one of the cases where the Scala compiler is unable to infer the type of an expression. But actually, a List[_] is a valid function from Int to something:
val f = List(99, 88, 77)
f(1) // -> 88
So for your code to compile, you have to give the compiler a little hint so it typechecks:
val list = List(1, 2, 3, 4)
list.map(List[Function[Int, Int]](_ + 1))
// ^^^^^^^^^^^^^^^^^^^^ type annotation
This is also valid:
list.map(List[Int => Int]](_ + 1))
It will compile but it'll fail at runtime, because you are trying to get elements 1, 2, 3 and 4 of a one-element list. If the list contained only zeros (the only valid index for that particular list) it'd work:
val list = List(0, 0, 0)
list.map(List[Function[Int, Int]](_ + 1))
// -> evaluates to a list of three functions
... or also if the list of functions contained enough elements for the index 1, 2, 3 and 4 to exist:
val list = List(1, 2, 3, 4)
list.map(List[Function[Int, Int]]( // a list of 5 functions:
_ + 1, // 0) the successor function,
_ * 10, // 1) the "append a zero" function,
Math.abs, // 2) the absolute value function,
_ / 2, // 3) the half function
x => 2 // 4) the constant function with value 2
))
// -> evaluates to a list of four functions. Can you guess which ones?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With