First-class functions
Scala's functions are the first-class functions (first-class function). Not only can you define and invoke functions, you can also write them as anonymous literals (literal) and pass them as values.
The function literal is compiled into the class and instantiated at run time as a function value. What do you mean? The essence of a function is an instance of a class. a function is a collection of attributes, and any function value is an instance of a class that extends one of several functionn traits of the Scala package, such as Function0 is a function without parameters, Function1 is a function with one parameter, and so on. Each functionn trait has an apply method to invoke the function.
Therefore, the difference between the function literal and the function value is that the function literal exists in the source code, and the function value exists as an object at run time. This distinction is very much like the relationship between the class (source code) and the object (run time).
Description
When you invoke an object, the line is called in a function.
Scala> Object addone extends Function1[int, int] {|defApply (m:int): Int = m+1| }defined Object addone Scala> AddOne (1) Res12:int =2//classes can also extend function, which instances of these classes can use () to invokeScala> class addone extends Function1[int, int] {|defApply (m:int): Int = m +1| }defined class addone Scala>ValPlusOne =NewAddOne () Plusone:addone = <function1>scala> PlusOne (1) Res0:int =2//You can use a more intuitive and fast extends (int = int) instead of extends Function1[int, int] class addone extends (int = int) { defApply (m:int): Int = m +1}
This trait defines the Apply syntax sugar, which helps unify the duality of object and functional programming.
Placeholder Simplification
Using anonymous function literals as arguments to another function, you can use placeholders _
for simplification. Here are a few simplified versions:
//高阶函数def hf(f:String => Unit) = f("higher"// 第1个简化版本higher//这里使用单个下划线替换整个参数列表// 第2个简化版本// 第3个简化版本// 第4个简化版本higher
Partial application functions
Some of the applied functions (partially applied function), as well as the translation of partial application functions, are expressions that you do not need to provide all the parameters required by the function, to provide only parts, or to provide no arguments.
An example is given below:
defval a = sum _a: (Int, Int, Int) => Int = <function3>scala> a(1236scala> a.apply(1236
In the code above, the Scala compiler uses a partial function expression, sum _
instantiates a function value with 3 missing integer arguments, and assigns the index of the new function value to variable a.
What actually happens is this: a variable named a points to a function value object. This function value is sum _
an instance of a class that is automatically generated by the Scala compiler according to a partial application function expression. The compiler produces a class that has an apply method with 3 parameters. The reason for taking 3 arguments is because sum _
the number of arguments missing for the expression is 3.
The Scala compiler simply passes the sum _
3 missing parameters to sum and returns the result, based on the Apply method in the class that the expression automatically generates.
Another use of this underscore for expressions that represent all parameter lists is the ability to convert a def-defined function to a function value. wrap the method or nested function in the function value by underlining the function name.
Partial function
The partially function is derived from the argument that the function is not applied to all of its parameters. In sum _
The example, it is not applied to any parameters and can be seen as a partial function. However, you can also express a partial function by providing some, but not all, of the required parameters.
Such as:
val b = sum(13)b: Int => Int = <function1>scala> b(26scala> b(59
This provides the first and last arguments to sum, but the intermediate parameters are missing. Because only one parameter is missing, the Scala compiler produces a new function class with an apply method with a parameter.
Closed Package
function values (objects) that are created at run time according to function literals are called closures (closure). The name is derived from the "close" behavior of the function literal by capturing the binding of the free variable.
function literals without free variables, such as (x: Int) => x + 1
, are called closed items (closed term). Therefore, the function value created at run time according to this function literal is not strictly a closure, because (x: Int) => x + 1
it is closed at the time of writing. But any function literal with free variables, such as (x: Int) => x + more
, is open term. Therefore, any (x: Int) => x + more
function value created for the template re-run will have to capture the binding to the free variable more
. The resulting function value will therefore contain an index to the more variable that is captured. and since the function value is the final product of the behavior of closing this open item (x: Int) => x + more
, it is called a closure.
As for the use and role of closures, I do not have a thorough understanding of their intentions, until after the accumulation of learning, and then for specific introduction.
Tail recursion
The last action in the function is to invoke the function's own behavior, called the tail recursion (tail recursive). The Scala compiler detects that the tail recursion updates the function parameter with the new value and then replaces it with a jump back to the beginning of the function. This compiler optimization ensures that you can use a more elegant and concise recursive scheme without any running time overhead.
Tail recursive function tracking
The tail recursive function will not create a new stack structure for each call, and all calls will be executed within a struct. This could surprise programmers who have checked the stack trace information of the program and failed.
def boom(x: Int): Int = { | if0thrownew Exception("boom!") | else boom(x-11 | }boom: (x: Int)Intscala> boom(3)java.lang.Exception: boom! at .boom(<console>:8) at .boom(<console>:9) at .boom(<console>:9) at .boom(<console>:9) 33 elided
The above function is not a tail recursion because the increment operation is performed after the recursive call, where you can see the information of the call stack.
def bang(x: Int): Int = { | if0thrownew Exception("bang!") | else bang(x-1) | }bang: (x: Int)Intscala> bang(5)java.lang.Exception: bang! at .bang(<console>:8) 33 elided
This is the form of a tail recursion, and we only see a stack structure of bang.
Tips: If you think you'll be confused by tail-recursive call optimizations when you see a stack trace, you can turn it off with a switch: -g:notailcalls
pass the arguments to the Scala shell or the Scalac compiler.
Tail recursion limitation
Tail recursion optimization qualifies a method or nested function that must be in the last action call itself, instead of going to a function value or any other intermediate function. Therefore, the use of indirect recursive calls or the last call is a function value can not get tail recursion optimization.
reprint Please indicate the author Jason Ding and its provenance
Gitcafe Blog Home page (http://jasonding1354.gitcafe.io/)
GitHub Blog Home page (http://jasonding1354.github.io/)
CSDN Blog (http://blog.csdn.net/jasonding1354)
Jane Book homepage (http://www.jianshu.com/users/2bd9b48f6ea8/latest_articles)
Baidu Search jasonding1354 access to my blog homepage
"Scala" prime functions and functions as objects