如果JavaScript中的递归步骤是块中的最后一个表达式,它只会优化为非递归循环(如果我理解正确)。这是否意味着以下代码中右侧的递归调用将被优化,而左侧的递归调用将不会被优化?
function fibonacci(n) {
if(n < 2) return n;
return fibonacci(n-1) + fibonacci(n-2);
}
如果JavaScript中的递归步骤是块中的最后一个表达式,它只会优化为非递归循环(如果我理解正确)。这是否意味着以下代码中右侧的递归调用将被优化,而左侧的递归调用将不会被优化?
function fibonacci(n) {
if(n < 2) return n;
return fibonacci(n-1) + fibonacci(n-2);
}
function fun1()
return fun2(42)
function fun2(arg)
return arg + 1
被翻译成这个
fun1:
push 42
call fun2
result = pop
push result
exit
fun2:
arg = pop
arg = arg + 1
push arg
exit
TCO(尾调用优化)可以消除掉 call-pop-push 的过程,直接跳转到 fun2
方法中:
fun1:
push 42
goto fun2
exit
fun1:
push n - 1
call fun2
result1 = pop
push n - 2
call fun2
result2 = pop
result3 = result1 + result2
push result3
exit
这里不可能用跳转替换调用,因为我们需要返回到fun1执行加法操作。
免责声明:这是一个相当理论化的解释,我不知道现代JS编译器实际上如何实现TCO。它们非常智能,所以也许有一种方法来优化这样的东西。
fun1
: “为调用fun2
创建一个堆栈帧,其中包含42
作为参数,在调用堆栈帧中捕获结果作为帧的返回值并弹出该帧”?任何关于跳转优化为什么有效的阐述也将非常有帮助。 - Ben Astonreturn 1 + myself();
可以被“优化”。 - user663031
fibonacci(n-1)
作为其自身递归的一部分几乎总是会调用fibonacci(n-2)
来进行优化,所以你可以进行优化。或者你可以有一个known_fib
列表,首先检查它,只有当一个数字不在列表中时才计算fibonacci()
。(后者将把fibonacci(n-2)
减少到单个查找)。 - Niet the Dark Absol