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

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.

主站蜘蛛池模板: 东光县| 建宁县| 万全县| 乃东县| 洪洞县| 常宁市| 南岸区| 安义县| 丰城市| 吴川市| 扶沟县| 金门县| 余干县| 晋城| 哈密市| 凤冈县| 龙川县| 泗阳县| 孝义市| 汶川县| 延庆县| 神木县| 凤城市| 临漳县| 德化县| 肃北| 安龙县| 大同市| 扶风县| 萍乡市| 马关县| 方正县| 阳谷县| 西宁市| 巴彦淖尔市| 怀柔区| 依兰县| 惠水县| 安吉县| 曲阜市| 海丰县|