What is the advantage of using multiple function parameter lists?

scala> def a(i:Int)(j:Int) = i * j a: (i: Int)(j: Int)Int scala> def b(i:Int, j:Int) = i * j b: (i: Int, j: Int)Int 

The two definitions are very similar, and they (seem to me) do the same.

Besides defining a function that receives implicit parameters or a block of code as a parameter, is there any reason to use the first definition style?

+4
source share
3 answers

The main reason for "currying" functions in this way is the possibility of partial application:

 scala> val c = a(5) _ c: Int => Int = <function1> 

Here c is a function that takes one int and returns the result of multiplying this int by 5. Perhaps you should set c with one method and pass it to another method that expects the function to take one Int parameter. A bit trivial in this case, but very flexible for various purposes.

+3
source

This is the list I compiled during this time:

1) Type resolution for multiple argument lists

 class ResourceManager { type Resource def open: Resource = ??? } class ResourceManagerTest { // Does not compile: def test1(rm: ResourceManager, r: rm.Resource) = ??? // Compiles: This way the type can be resolved def test2(rm: ResourceManager)(r: rm.Resource) = ??? } 

2) Type inference where earlier arguments can "block" type parameters for later arguments (thanks to Myserious Dan)

  def foo1[A](x: A, f: A => Int) = ??? def foo2[A](x: A)(f: A => Int) = ??? def foo1foo2Demo() { // This will always demand a type annotation on any anonymous function // you pass in: foo1(1, (i: Int) => i * i) // Does not compile: foo1(1, i => i * i) // Type not required foo2(2)(i => i * i) } 

3) Language extensions with syntax

 object MultipleArgumentListsDemo { // This style of function definition allows syntax-like language extensions @tailrec def myWhile(conditional: => Boolean)(f: => Unit) { if (conditional) { f myWhile(conditional)(f) } } def myWhileDemo() { var count = 0 myWhile(count < 5) { count += 1 println(count) } } 

4) Having both implicit and implicit arguments , since implicit is a modifier for the entire list of arguments:

  def f[A](x: A)(implicit mf: Manifest[A]) { } 

5) A parameter value from one parameter list can be used to calculate the default value in another parameter list, but not in the same one.

  def g(x: Int)(y: Int = x * 2) = { x + y } 

6) Multiple repeated argument lists ("varargs")

  def h(as: Int*)(bs: Int*)(cs: Int*) = as.sum * bs.sum * cs.sum 

7) Partial application

  def i() { val foop = h(1, 2, 3)(4, 5, 6, 7, 9) _ println(foop(Seq(10, 11))) } 

Since I did not track my sources while I was compiling this list over time: it is possible that some or all of the examples are copied from other sources (other questions on SO), so please leave a note and I will add a link from where it came from.

+6
source

Additionally, to support currying, it also helps with type inference: Sometimes the compiler cannot infer the correct type if everything is in the same argument list, but if you separate the part that depends on the binding of other arguments, it works. A typical example is foldLeft : try to implement it with a single argument list, and then in some cases the compiler needs type annotations.

+1
source

Source: https://habr.com/ru/post/1495862/


All Articles