简体   繁体   中英

What is the difference between this two Scala definitions

I have the below 2 definitions in Scala, Which gives me the same result. But It's bit different from each other.

def sum(f: Int => Int)(a: Int, b: Int): Int =
if (a > b) 0 else f(a) + sum(f)(a + 1, b)     //> sum: (f: Int => Int)(a: Int, b: Int)Int

sum(x => x*x)(1,2)   //> res3: Int = 5  

The second one is

def sum(f: Int => Int,a: Int, b: Int): Int =
if (a > b) 0 else f(a) + sum(f,a + 1, b)      //> sum2: (f: Int => Int, a: Int, b: Int)Int

sum(x => x*x,1,2)                               //> res4: Int = 5

The only different I see is sum(f: Int => Int,a: Int, b: Int) and sum(f: Int => Int)(a: Int, b: Int) . In the latter case the function parameter and the values parameters are separated.

What is this behavior. Is this really a same or is there a different between them ?

With respect to the way that you're using them they are pretty much identical. But the first version has some additional flexibility (and utility) in general.

For example

val g = sum(x => x*x) _  //g has type (Int, Int) => Int
println(g(2, 3))         //prints 13

This is called currying. You can do this with more than two argument lists, eg

def foo(b: Boolean)(i: Int)(s: String)(d: Double): Int = ...
val g = foo(true) _  //g has type Int => (String => (Double => Int))
val h = g(3) _       //h has type String => (Double => Int)
val r = h("asdf") _  //r has type Double => Int

The underscore can sometimes be left off depending on the context, eg

val r: Int => Double = foo(true)(3)("asdf")

Multiple argument lists are also used for implicit parameters, as well as at times when the Scala compiler needs some help with the type inferencing. When used together with call-by-name parameters they can also be handy for creating fake syntax or control structures via libraries, eg

def repeat(n: Int)(body: => Unit) { 
  var i = n
  while (i > 0) { i -= 1; body }
}

var counter = 0
repeat(10) {                  //This method call (repeat) looks a bit like a part                   
  println(s"Hello: $counter") //of the language due to call-by-name argument, 
  counter += 1                //multiple parameter lists, use of curly braces, etc.
} 

results in

Hello: 1 Hello: 2 . . . Hello 9

Yes, they are the same. You can use multiple parameter blocks for several reasons, none of which apply here:

  1. To help type inference with generic methods (eg if you have def foo[A](a: A, f: A => A) and call foo(1, _ + 1) you might expect the compiler to understand that A is Int . But it can't do that before determining the type of _ + 1 . If you use def foo[A](a: A)(f: A => A) instead, it'll work.

  2. To use previous arguments in default values. Eg def foo(x: Int, y: Int = x) doesn't compile, def foo(x: Int)(y: Int = x) does.

  3. A function argument by itself can be written in braces without parentheses:

     def sum(a: Int, b: Int)(f: Int => Int): Int sum(1, 2) { x => x*x } 
  4. The last block can contain implicit parameters .

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