Scala optimizes tail recursion and even provides specific annotations that tell the compiler that it needs to be optimized for tail recursion. However, this optimization is limited to strict tail recursion, indirect recursion, etc., and will not be optimized.
Concept of tail recursion
Recursion, everyone is not strange, a function directly or indirectly call itself, is recursive. Let's look at a simple, computational factorial example.
def factorial (n:int): Int = { if(n <= 1) 1 else n * factorial (n-1)}< /c6>
The above factorial method, when n>1, needs to invoke itself, which is a typical recursive call. If n=5, then this recursive call process is roughly the following:
Factorial (5)5 * factorial (4)5 * (4 * factorial (3))5 * (4 * (3 * factorial (2)))5 * (4 * (3 * (2 * factorial (1))) 5 * (4 * (3 * (2 * 1))) 120
Recursive algorithm, generally simple, in line with people's way of thinking, but because of the need to maintain the call stack, the efficiency is low, when the number of calls more often run out of memory. As a result, programmers often implement the original version recursively, then optimize it and rewrite it as a loop to improve performance. The end of recursion is entered into the eyes of people.
So, what is tail recursion? Tail recursion means that the recursive call is the last statement of the function, and the result is returned directly, which is a special kind of recursive invocation. Because recursive results are always returned directly, the tail recursion is easier to convert to a loop, so the compiler can easily optimize it. Many compilers now have optimizations for tail recursion, and programmers no longer have to manually rewrite them as loops.
The factorial function above is not a tail recursion, because the result of a recursive call has an extra multiplication calculation, which causes the data to remain on the stack for each recursive call. We can change it to a tail-recursive way.
def Factorialtailrec (N:bigint, acc:bigint): BigInt = { if(n <= 1) ACC C6>else Factorialtailrec (n-1, acc * N)}
Now we look at the invocation process, it's not the same, factorialtailrec each time the results are returned directly. Or take n=5 as an example, this time the invocation process is as follows.
Factorialtailrec (5, 1) Factorialtailrec (4, 5) //1 * 5 = 5Factorialtailrec (3,)//5 * 4 =FA Ctorialtailrec (3)//3 =Factorialtailrec (2, +)//* 2 =Factorialtailrec (1, 120 )//120 * 1 = 120120
The above call, because the call results are returned directly, so the data left on the stack before the recursive call can be discarded, only need to keep the last data, this is the reason for the tail recursion is easy to optimize, and its secret weapon is the above ACC, it is an accumulator (accumulator, It is customary to translate into accumulators, in fact not necessarily "plus", any form of accumulation can be used to accumulate the results of previous calls, so that the data before the call can be discarded.
Source: Http://meetfp.com/zh/blog/tail-recursion
Scala Tail recursion (tail recursion)