Reputation: 12768
Given
scala> def method(x: Int) = x
method: (x: Int)Int
scala> val func = (x: Int) => x
func: Int => Int = <function1>
Consider the following code:
scala> method _
res0: Int => Int = <function1>
scala> func(_)
res1: Int => Int = <function1>
scala> func _
res2: () => Int => Int = <function0>
I can understand that res0
is eta expansion and res1
is equivalent to lambda function (x) => func(x)
. But I cannot figure out the output of res2
. Could anyone please explain that for me?
Upvotes: 6
Views: 1739
Reputation: 170713
This is actually a bit tricky. First, let's see what happens outside REPL:
It doesn't work when func
is a local variable:
object Main extends App {
def foo() = {
val f = (_: Int) + 1
f _
}
println(foo())
}
[error] /tmp/rendereraEZGWf9f1Q/src/main/scala/test.scala:8: _ must follow method; cannot follow Int => Int
[error] f _
[error] ^
But if you put it outside def foo
, it compiles:
object Main extends App {
val f = (_: Int) + 1
val f1 = f _
println(f1)
}
because f
is both a field of Main
and a method without arguments which returns the value of this field.
The final piece is that REPL wraps each line into an object (because Scala doesn't allow code to appear outside a trait/class/object), so
scala> val func = (x: Int) => x
func: Int => Int = <function1>
is really something like
object Line1 {
val func = (x: Int) => x
}
import Line1._
// print result
So func
on the next line refers to Line1.func
which is a method and so can be eta-expanded.
Upvotes: 8
Reputation: 4753
To answer your question about res2
- the appended underscore _
syntax is used to partially apply a function.
So.
scala> func _
Means you have partially applied your <function1>
.
This results in a new curried form, the first function of which takes zero arguments (hence <function0>
)
() =>
Which returns your original <function1>
which takes 1 argument.
Int => Int = <function1>
The complete result being the chain of functions.
res2: () => Int => Int = <function0>
The rule that might be useful for you to remember is that functions associate to the right so the following are equivalent.
() => Int => Int
() => (Int => Int)
This other post might be useful reading for you.
Upvotes: 4
Reputation: 2101
val func1 = func _
This returns a function0 which takes no arguments and returns the func
function.
You can use this like:
func1()(2) // outputs 2
You can continue doing this kind of expansion ad infinitum:
val func2 = func1 _
func2()()(2) // outputs 2
Upvotes: 2
Reputation: 23502
You've used the eta Expansion to turn res2
into a function that takes 0 parameters and returns a function that takes a single parameter.
res2: () => Int => Int = <function0>
So you can now do this:
val zero = func _
val f: Int => Int = zero()
Upvotes: 3