简体   繁体   中英

Scala Syntax Help Currying

I came across some code in scala in a similar form like this:

  def test1(f : Int => Int)(x : Int) = x + f(x)

  def test2(f : Int => Int)(x : Int) = f(x)

  test2(test1(x => 2*x))(2)

I'm confused, so function test1 takes a function and a Int as parameters, and returns a function, right? Then how can test1(x => 2*x) be valid and returns a function to test2? Apparently it takes 2 asthe integer parameter, but why? How does the statement test2(test1(x => 2*x))(2) expand?

Thanks in advance.

function test1 takes a function and a Int as parameters, and returns a function, right?

No, it only takes a function as its argument and returns a function. The returned function then takes an int as the argument and returns an int.

Then how can test1(x => 2*x) be valid and returns a function to test2?

I hope that's clear now.

How does the statement test2(test1(x => 2*x))(2) expand?

test1 is called with x => 2*x as the argument and returns a function. Then test2 is called with that returned function as its argument and returns another function. Then that other function is called with 2 as its argument.

This:

test2(test1(x => 2*x))(2)

expands to this:

test2(y => test1(x => 2*x)(y))(2)

Scala's methods with multiple argument lists can act a lot like curried functions in other languages, but in fact are implemented as methods that requires all of their parameters, and this does show through in the syntax. For example if you put this into the REPL:

test1(x => 2*x)

It will complain about missing arguments. What this syntax does allow is "eta-expansion", where a method is converted into a function. If you write:

val func: Int => Int = test1(x => 2*x) _

You can get a function that represents test1 partially applied. Scala will do eta-expansion automatically if the context requires it, which is what happens with test2(test1(x => 2*x))(2) . Note that test1 itself never returns a function, but the compiler will build a function based on it when required.

However, if you define test1 like:

def test1(f : Int => Int) = (x : Int) => x + f(x)

Then the compiler will accept test1(x => 2*x) without the _ . Also, in the underlying implementation there will be only one class implementing the closure retured by test1 , whereas with the original definition every partial application of test1 causes a new class to be created for it. On the other hand, it is less efficient when given both parameters, because the closure is always created.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM