Lifu Huang
Lifu Huang

Reputation: 12768

Underscore after function?

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

Answers (4)

Alexey Romanov
Alexey Romanov

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

jacks
jacks

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

Samar
Samar

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

Luka Jacobowitz
Luka Jacobowitz

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

Related Questions