1 回答

TA贡献1998条经验 获得超6个赞
与其使用loop/ recur(我认为这是一种丑陋和不必要的hack),不如考虑使用folds:
const recNat = (zero, succ) => n => {
let result = zero;
while (n > 0) {
result = succ(result);
n = n - 1;
}
return result;
};
const mul = x => y => x * y;
const pow = x => recNat(1, mul(x));
console.log([0,1,2,3,4,5,6,1e6].map(pow(2))); // [1,2,4,8,16,32,64,Infinity]
几乎每个递归函数都可以使用折叠来定义(也称为结构递归,又称为归纳)。例如,甚至可以使用折叠来定义Ackermann函数:
const recNat = (zero, succ) => n => {
let result = zero;
while (n > 0) {
result = succ(result);
n = n - 1;
}
return result;
};
const add = x => y => x + y;
const ack = recNat(add(1),
ackPredM => recNat(ackPredM(1),
ackMPredN => ackPredM(ackMPredN)));
console.time("ack(4)(1)");
console.log(ack(4)(1)); // 65533
console.timeEnd("ack(4)(1)");
上面的代码段大约需要18秒才能在笔记本电脑上计算出答案。
现在,您可能会问为什么我recNat使用迭代而不是自然递归来实现:
const recNat = (zero, succ) => function recNatZS(n) {
return n <= 0 ? zero : succ(recNatZS(n - 1));
};
我使用迭代的原因与您使用迭代实现的原因相同loop。踩踏。通过为要折叠的每种数据类型实现不同的蹦床,您可以编写功能代码,而不必担心堆栈溢出。
底线:使用折叠而不是显式递归。它们比您想像的强大得多。
添加回答
举报