【发布时间】:2016-05-06 00:20:46
【问题描述】:
我以尾递归和延续传递方式实现了map。两个版本非常相似:
var inc = x => ++x;
var xs = [1,2,3,4,5];
var mapR = f => xs => {
var rec = acc => {
acc[acc.length] = f(xs[acc.length]);
return acc.length < xs.length ? rec(acc) : acc;
}
return rec([]);
}
mapR(inc)(xs); // [2,3,4,5,6]
var mapC = f => xs => cc => {
var rec = acc => cc => {
acc[acc.length] = f(xs[acc.length]);
return acc.length < xs.length ? cc(acc)(rec) : acc;
}
return cc(rec([])(rec));
}
mapC(inc)(xs)(console.log.bind(console)); // [2,3,4,5,6]
我显然也可以写rec(acc),而不是cc(acc)(rec)。我的结论是否正确,尾递归只是 CPS 的一个特例,而用 var rec = acc => {...} 编写的 mapC 是正确的 CPS 函数?
【问题讨论】:
-
实际上,对于真正的 CPS,您永远不应该
return。还假设f继续。 -
@Bergi 但是
() => { a(); }变成了() => { a(); return undefined; }因此a将不再处于尾部位置,或者你的意思是什么? -
我的意思是 CPS 是 steriods 的尾调用,没有真正返回任何东西 - 你没有调用堆栈,你只是跳到下一个延续。当然,这需要一个特殊的解释器,这实际上是一种可怕的编程风格,但是已经构建了 poc :-)。仅当您从非 cps 代码调用 cps 时,
returns 才有意义。
标签: javascript tail-recursion continuations