Partial application and functions

Until now, the methods and variables were handled the same way by the compiler. Can we exploit the similarities further and return a method as a result of another method and store it into the variable? Let's give it a try:

scala> object Functions {
| def method(name: String) = {
| def function(in1: Int, in2: String): String = name + in2
| function
| }
| val function = method("name")
| }
function
^
On line 4: error: missing argument list for method function
Unapplied methods are only converted to functions when a function type is expected.
You can make this conversion explicit by writing `function _` or `function(_,_)` instead of `function`.

Unfortunately, it didn't work. We tried to create and return a function from within a method and assign this function to a variable, but the compiler does not allow this. However, it gives us a useful hint about what we are doing wrong!

It turns out that functions and methods are different for the compiler and methods can only be passed in the form of an instance of the enclosing class. This distinction is related to the fact that everything in the JVM is represented as an instance of some class. Because of this, the methods we define become methods of the class, and methods are not first-class citizens in the JVM. Scala works around this approach by having a hierarchy of classes representing functions of different arities. Thus, in order for us to be able to return a method from another method, the former must become a function. And the compiler gave us a hint as to how to achieve this: by using _ (underscore) in the place where the parameters are expected.

scala> object Functions {
| def method(name: String) = {
| def function(in1: Int, in2: String): String = name + in2
| function _
| }
| val function = method("name")
| }
defined object Functions

The partial application can have two forms: a single underscore replacing the whole parameter list, or a single underscore replacing each parameter. Thus, for the partial application of the function we've just defined, both function _ or function(_,_) would be appropriate. 

The partial application syntax can be used to create shortcuts for functions defined elsewhere, by importing and partially applying them at the same time:

val next = Math.nextAfter _
next(10f, 20f)
val / = Math.hypot(_, _)
/ (10 , 20)

In general, for the function of N parameters, the partial application means specifying 0 =< M < N parameters and leaving the rest undefined, basically applying the function to some part of the parameter list. This partial application gives a function of (N-M) parameters and the same type of result as the original function back. In our previous example, we defined M to be zero and thus the signature of the resulting function remained unchanged. But the very fact of there being a partial application has converted our method into the function, which allowed us to further work with it as with a value.

In the case, if 0< M <N,  the underscores go into the place of the parameters that are not applied at the moment:

def four(one: String, two: Int, three: Boolean, four: Long) = ()
val applyTwo = four("one", _: Int, true, _: Long)

We applied the first and third arguments and left the second and fourth unapplied. The compiler requires us to provide a type ascription for missing parameters in order to use it while inferring the type of the resulting function.

The parameter names defined for methods are lost during the partial application and so are default values. The repeated parameters are converted to the Seq.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.195.111