TL;DR: the argument of the lambda can be inserted at an unexpected position. Instead of taking
a foreach { println(_.blah) }
and building
a foreach { x => println(x.blah) }
out of it, the compiler instead builds
a foreach { println( x => x.blah ) }
and then fails to derive the type for the argument x
.
A) This is the most explicit way to write down the lambda, the only way to make it clearer would be to add a type:
a foreach { perA => println(perA * 2) }
is the same as
a foreach { (x: Int) => println(x * 2) }
This should obviously work.
B) This works because it's one way to write down the function automatically generated from println
. It is equivalent to any of the six variants below:
a foreach { (x: Int) => println(x) }
a foreach { x => println(x) }
a foreach { println(_) }
a foreach { println _ }
a foreach { println }
a foreach println
C) Because of the * 2
, this here
a foreach { println(_ * 2) }
can no longer be considered just println(_)
. Instead, it is interpreted as
a foreach { println( { (x: ??!) => x * 2 } ) }
and since println
takes no function-valued arguments, it cannot determine what the type of x
is supposed to be, and exits with an error.
D) Is essentially the same as A, it works, I hope it's clear.
E) Is a variation of C, but this time, the type-checker isn't looking for something with method *(i: Int)
, but instead it's looking for something with a member para
.
This here:
b foreach { println(_.para) }
is again interpreted as a foreach
with a function which ignores elements of b
and returns the constant value of the expression println(_.para)
,
that is:
b foreach { println( { (x: ??!) => x.para } ) }
Again, the inner expression println( { (x: ??!) => x.para } )
does not make any sense, because println
does not expect function-valued arguments (it can handle Any
, but it's not enough to derive the type of x
).