2
我一直在閱讀JavaScript中的遞歸函數和尾部調用優化(TCO)。我的目標是克服在遞歸函數的棧溢出:在JavaScript中封裝尾部優化的實用程序?
function factorial(n) {
function recur(n, acc) {
if (n === 0) {
return acc;
} else {
return recur(n - 1, n * acc);
}
}
return recur(n, 1);
}
factorial(5); // 120
console.log(factorial(4585759)); // Maximum call stack size exceeded
我已經找到了如何使用thunk
和trampoline
克服遞歸函數的棧溢出:
let thunk = function (fn) {
return function() {
let args = Array.prototype.slice.apply(arguments);
return function() { return fn.apply(this, args); };
};
};
function trampoline(f) {
while (f && f instanceof Function) {
f = f();
}
return f;
}
function factorial(n) {
let recur = function(x, n) {
if (n === 0) {
return x;
} else {
return thunk(recur)(n * x, n - 1);
}
};
return trampoline(thunk(recur)(1, n));
}
console.log(factorial(5)); // 120
console.log(factorial(4585759)); // Infinity
然而,我不喜歡我被迫寫遞歸函數的方式。我發現了一個函數的一些實現命名TCO
:
function tco(fn) {
var active, nextArgs;
return function() {
var result;
nextArgs = arguments;
if (!active) {
active = true;
while (nextArgs) {
result = fn.apply(this, [nextArgs, nextArgs = null][0]);
}
active = false;
}
return result;
};
}
功能應該允許如下:
let factorialToc = tco(function(n) {
function recur(n, acc) {
if (n === 0) {
return acc;
} else {
return recur(n - 1, n * acc);
}
};
return recur(n, 1);
});
但它不工作:
factorialToc(5); // 120
console.log(factorialToc(4585759)); // Maximum call stack size exceeded
是否有任何實用功能封裝TCO?
'return n * factorial(n - 1);'是*不是*尾部調用。你永遠不會得到一個優化。 – Bergi
我已經更新了階乘的實現,它現在應該工作嗎? –