假设我有一个名为 f 的函数,它接受一个名为 x 的整数参数并返回一个整数。我还有一个整数 n 表示函数必须调用自身的次数。因此,例如,如果我的函数调用f(x)
在 n = 1 时看起来像这样,那么f(f(f(x)))
当 n = 3 时它看起来像这样。在下面的示例中怎么会这样:
function succ(n) {
return function (f, x) {
return f(x);
};
}
假设我有一个名为 f 的函数,它接受一个名为 x 的整数参数并返回一个整数。我还有一个整数 n 表示函数必须调用自身的次数。因此,例如,如果我的函数调用f(x)
在 n = 1 时看起来像这样,那么f(f(f(x)))
当 n = 3 时它看起来像这样。在下面的示例中怎么会这样:
function succ(n) {
return function (f, x) {
return f(x);
};
}
您可以在内部函数内部循环:
for(let i = 0; i < n; i++) x = f(x);
return x;
或者让你的函数自己调用:
return n > 0 ? succ(n - 1)(f, f(x)) : x;
我们可以核心递归地表达这个算法。Corecursion 从起点开始在前进的道路上构建其结果:
const iterate = f => x =>
[x, () => iterate(f) (f(x))];
const main = iterate(x => x * 2) (1);
console.log(
main[1] () [1] () [1] () [1] () [1] () [1] () [1] () [1] () [0]); // 256
这只是一个概念证明,而不是我们真正想要的。我们如何避免笨拙的界面?我们可以使用 aProxy
使非参数函数隐含。它与惰性属性 getter 的机制基本相同。此外,我们不想手动访问流中的值,而是使用方便的函数:
class ThunkProxy {
constructor(f) {
this.memo = undefined;
}
get(g, k) {
if (this.memo === undefined)
this.memo = g();
if (k === THUNK)
return true;
else if (k === Symbol.toPrimitive)
return () => this.memo;
else if (k === "valueOf")
return () => this.memo;
else return this.memo[k];
}
}
const THUNK = "thunk";
const thunk = f =>
new Proxy(f, new ThunkProxy(f));
const iterate = f => x =>
[x, thunk(() => iterate(f) (f(x)))];
const takeNth = n => ([head, tail]) =>
n === 0
? head
: takeNth(n - 1) (tail);
const main = iterate(x => x * 2) (1);
console.log(
main[1] [1] [1] [1] [1] [1] [1] [1] [0]); // 256
console.log(
takeNth(16) (main)); // 65536
您可以构建一个times
高阶函数并使用它来包装其他函数......
const times = (fn, n) => (...args) => {
if (!n) { return; }
fn(...args);
return times(fn, n - 1)(...args);
}
const log10 = times(console.log, 10);
log10('hello');