Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala - Confusion with lambda in map function

Tags:

lambda

scala

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.

like image 413
oks16 Avatar asked May 31 '26 17:05

oks16


2 Answers

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.

like image 125
Marth Avatar answered Jun 03 '26 14:06

Marth


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?
like image 42
Roberto Bonvallet Avatar answered Jun 03 '26 13:06

Roberto Bonvallet



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!