您可以将蹦床视为程序中优化的编译器优化。因此,是什么使我们无法以完全相同的方式来适应更通用的优化技术。
这是尾递归模态缺点的草图:
const loop = f => {
let step = f();
while (step && step[step.length - 1] && step[step.length - 1].type === recur) {
let step_ = step.pop();
step.push(...f(...step_.args));
}
return step;
};
const recur = (...args) =>
({type: recur, args});
const push = (xs, x) => (xs.push(x), xs);
const map = f => xs =>
loop((i = 0) =>
i === xs.length
? []
: push([f(xs[i])], recur(i + 1)));
const xs =
map(x => x * 2) (Array(1e6).fill(0).map((x, i) => i))
.slice(0,5);
console.log(xs); // [0, 2, 4, 6, 8]
这种优化取决于表达式的关联性。乘法也具有关联性,因此存在尾递归模乘。但是,我必须作弊才能在Javascript中实现它:
const loop = f => {
let step = f();
const acc = [];
while (step && step[1] && step[1].type === recur) {
acc.push(step[0]);
step = f(...step[1].args);
}
return acc.reduce((acc, f) => f(acc), step);
};
const recur = (...args) =>
({type: recur, args});
const mul = x => step => [y => x * y, step];
const pow = (x_, n_) =>
loop((x = x_, n = n_) =>
n === 0 ? 1
: n === 1 ? x
: mul(x) (recur(x, n - 1)));
console.log(
pow(2, 1e6)); // Infinity, no stack overflow
如您所见,我不能使用mul
不是特别令人满意的Regular 。这与Javascript蜜蜂语言紧密相关吗?有没有更好的方法来实现JS中的尾递归模乘而不必引入笨拙的二进制运算符?
米琪卡哇伊
相关分类