Tail call optimization in Scala
2015-10-02 15:29
281 查看
Recursion provides us an clean way to solve some algorithm problems. But one drawback of it is the memory cost caused by recursion call stack, especially when memory is sensitive like in mobile applications.
One alternative is using a while loop instead of recursion, but while loop usually is not as easy as recursion. So most of the time, we will come up with solutions using recursion, after that will try to convert it into a while loop style algorithm. But
actually in some languages like Scala, it does provide the build-in support to compile the "special recursion" code to a while loop style. The"special recursion" here means that your recursion call should always be in a tail position, that is the caller does
nothing other than return the value of the recursive call.
Let's take the fibonacci number problem for an example. Usually our solution would be like below:
Here since the recursion caller in position 1 does more than just returning the recursive call result, instead there is an add operation inside, which means we need special memory to store these temporary values as well as the call stacks. But if we try to
write it in a tail-recursive way, things will be different.
Notice that the recursion caller in position 2, it only returns the result of recursive call, in this way, Scala will help to compile tail-recursive function into a while-loop function, which is exactly what we want.
Now suppose that a super fibonacci, where f(x) = f(x-1) + f(x-2) + f(x-3), in the same approach, our code will be like this:
Writing your recursion in a tail-call style, sometimes is a basic optimization for your program, helping to avoid the memory cost cased by the call stacks. By the way, in Scala it only works when you do the recursive call directly using the function itself,
below two cases will not work:
One alternative is using a while loop instead of recursion, but while loop usually is not as easy as recursion. So most of the time, we will come up with solutions using recursion, after that will try to convert it into a while loop style algorithm. But
actually in some languages like Scala, it does provide the build-in support to compile the "special recursion" code to a while loop style. The"special recursion" here means that your recursion call should always be in a tail position, that is the caller does
nothing other than return the value of the recursive call.
Let's take the fibonacci number problem for an example. Usually our solution would be like below:
def fibonacci(x: Int): Int = { if (x <= 2) x - 1 else fibonacci(x - 1) + fibonacci(x - 2) ------(1) }
Here since the recursion caller in position 1 does more than just returning the recursive call result, instead there is an add operation inside, which means we need special memory to store these temporary values as well as the call stacks. But if we try to
write it in a tail-recursive way, things will be different.
def fibonacci(x: Int, acc1: Int, acc2: Int): Int = { if (x <= 2) acc2 else fibonacci(x - 1, acc2, acc1 + acc2) --------(2) }
Notice that the recursion caller in position 2, it only returns the result of recursive call, in this way, Scala will help to compile tail-recursive function into a while-loop function, which is exactly what we want.
Now suppose that a super fibonacci, where f(x) = f(x-1) + f(x-2) + f(x-3), in the same approach, our code will be like this:
def sfibonacci(x: Int, acc1: Int, acc2: Int, acc3: Int): Int = { if (x <= 3) acc3 else sfibonacci(x - 1, acc2, acc3, acc1 + acc2 + acc3) }
Writing your recursion in a tail-call style, sometimes is a basic optimization for your program, helping to avoid the memory cost cased by the call stacks. By the way, in Scala it only works when you do the recursive call directly using the function itself,
below two cases will not work:
// case 1 val a = fibonacci _ def fibonacci(x: Int, acc1: Int, acc2: Int): Int = { if (x <= 2) acc2 else a(x - 1, acc2, acc1 + acc2) } // case 2 def fibonacci2(x: Int, acc1: Int, acc2: Int): Int = { if (x <= 2) acc2 else fun(x - 1, acc2, acc1 + acc2) } def fun(x: Int, acc1: Int, acc2: Int): Int = { fibonacci2(x, acc1, acc2) }
相关文章推荐
- 信号量sem_wait()的使用
- 关于信号量sem_wait的整理(转)
- system()函数 http://blog.csdn.net/ghevinn/article/details/7916126
- waitpid系统调用在Linux函数库中的原型是:http://blog.sina.com.cn/s/blog_602a39250100xfxx.html
- poj2305-Basic remains(进制转换 + 大整数取模)
- HDU 1702 ACboy needs your help again!(栈和队列)
- poj 1995 Raising Modulo Numbers【快速幂】
- 解决:CWnd::SetWindowText报Assertion failure
- AIDL调用第三方应用程序服务中的方法
- wait函数返回值总结http://blog.csdn.net/astrotycoon/article/details/41172389
- system函数的总结 http://blog.csdn.net/astrotycoon/article/details/40626355
- 【MongoDB】2014-07-25T11:00:48.634+0800 warning: Failed to connect to 127.0.0.1:27017, reason: errno:1
- linux避免僵死进程方法总结 http://blog.csdn.net/astrotycoon/article/details/39717143
- waitpid(or wait)和SIGCHILD的关系 http://blog.csdn.net/liuxingen/article/details/38350347
- Linux的system()和popen()差异 http://blog.csdn.net/liuxingen/article/details/47057539
- Sails的简单学习
- Treat your machine fair
- Learning Spark - LIGHTNING-FAST DATA ANALYSIS 第四章 - (4)
- Aizu 2304 Reverse Roads
- Aizu 2300 Calender Colors dfs