官术网_书友最值得收藏!

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.

主站蜘蛛池模板: 望城县| 湘阴县| 兴海县| 阳朔县| 攀枝花市| 兰溪市| 伊宁县| 营口市| 秭归县| 丰镇市| 湖口县| 微山县| 莱芜市| 原平市| 同心县| 华安县| 营口市| 陇南市| 湟源县| 登封市| 汾阳市| 大同市| 天等县| 万载县| 河池市| 开原市| 宜州市| 彰化市| 鹤壁市| 凌云县| 博客| 广水市| 康马县| 乐东| 池州市| 新蔡县| 宝清县| 宁津县| 襄汾县| 元江| 莎车县|