Knight71
Knight71

Reputation: 2949

what does double parameterized function means in scala?

I was going through the test code for spark. While I understand the logic behind the function given below

What does it means and What is the benefit of defining in the below syntax ?


Test Code

def withStreamingContext[R](ssc: StreamingContext)(block: StreamingContext => R): R = {
try {
  block(ssc)
} finally {
  try {
    ssc.stop(stopSparkContext = true)
  } catch {
    case e: Exception =>
       logError("Error stopping StreamingContext", e)
   }
  }
} 

why does it has to be defined this way ? why can't it be

def withStreamingContext[R](ssc: StreamingContext,block: StreamingContext => R): R = 

Upvotes: 3

Views: 126

Answers (4)

user3248346
user3248346

Reputation:

This style of declaring functions is referred to as currying. It was independently introduced by Moses Schönfinkel, and then later by Haskell Curry from where it takes its name. The concept actually originates in mathematics and then introduced into computer science.

It is often conflated with partial function application; the main difference is that a call to a partially applied function returns the result immediately, not another function down the "currying" chain.

scala> def foo (x:Int, y:Int, z:Int) : Int = x + y + z
foo: (x: Int, y: Int, z: Int)Int

scala> val pa = foo(1, _:Int, _:Int)
pa: (Int, Int) => Int = <function2>

scala> pa(2,3)
res0: Int = 6

In contrast, given f:(x,y,z) -> n, currying produces f':x -> (y -> (z -> n)). In other words, applying each argument in turn to a single argument function returned by the previous invocation. After calling f'(1), a function that takes a single argument and returns another function is returned, not a function that takes two arguments. In contrast partial function application refers to the process of fixing a number of arguments to a function, producing another function of smaller arity. These two are often conflated.

The benefits/advantages of currying have already been mentioned elsewhere. The main issue you had was understanding the syntax and it's origins which has been explained.

Upvotes: 1

slouc
slouc

Reputation: 9698

Well, it can. Separating arguments into two or more parameter lists is called currying. This way a two-parameter function can be turned into a function that takes one argument and returns a function that takes one argument and returns the result. This is what happened in the code you posted. Every n-parameter function can be seen as n 1-parameter functions (in fact, in Haskell all functions are treated like this).

Note that Scala also has a concept of partially applied functions, which boils down to the same thing. Both PAF and currying allow you to only pass a subset of parameters, thus receiving a function that takes the rest.

For example,

def sum(x: Int, y: Int) = x + y

can be curried and then you could say, for example:

def sum(x: Int)(y: Int) = x + y
def addTwo = sum(2) _ // type of addTwo is Int => Int

which gives you the same function, but with its first parameter applied. Using PAF, it would be

def sum(x: Int, y: Int) = x + y
def addTwo = sum(2, _: Int)

Upvotes: 3

Tomasz Błachut
Tomasz Błachut

Reputation: 2507

First of all

def a(x: Int)(y: Int) = x * y

Is a syntactic sugar for

def a(x: Int) = (y: Int) => x * y

That means that you define a method that returns a function (closed over x) You can invoke such method without all parameter lists and pass returned function around. You can also partially apply any other method but I think this syntax is cleaner.

Moreover, functions/methods with unary parameter lists can be invoked with expression syntax.

withStreamingContext(ssc) {
  // your code block passed to function
}

Upvotes: 1

Markus1189
Markus1189

Reputation: 2869

It is more convenient to use:

withStreamingContext(ssc) {
  doSomething()
  doSomethingElse()
}

vs

withStreamingContext(ssc, { doSomething(); doSomethingElse() })

Upvotes: 1

Related Questions