内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用
是否有某种方法可以通过高阶函数“包装”递归函数,从而使递归调用也被包装?
例如,假设我们有一个函数,sum()
,它通过将头添加到尾的和返回数字列表的和:
function sum(a) { if (a.length === 0) { return 0; } else { return a[0] + sum(a.slice(1)); } }
有没有办法写高阶函数,logging()
,这需要sum()
函数作为输入,并返回一个函数,该函数将参数输出到sum()
在每个递归调用上?
以下内容不起作用:
function logging(fn) { return function(a) { console.log(a); return fn(a); } } sum2 = logging(sum); sum2([1, 2, 3]);
实际产出:
[1, 2, 3] -> 6
预期产出:
[1, 2, 3] [2, 3] [3] [] -> 6
如果sum()
是否被重写,以便它可以与Y组合器样式的“递归”一起使用?
function sum_core(g) { return function (a) { if (a.length === 0) { return 0; } else { return a[0] + g(a.slice(1)); } }; } sum = Y(sum_core); sum([1, 2, 3]); // -> 6
如果你想要一个函数traceSum
:
> traceSum([1, 2, 3]); [1, 2, 3] [2, 3] [3] [] 6
你可以实现traceSum
详情如下:
function traceSum(a) { console.log(a); if (a.length === 0) return 0; else return a[0] + traceSum(a.slice(1)); }
通过这个实现,我们可以创建一个广义的trace
职能:
function trace(f) { return function (a) { console.log(a); return f(trace(f), a); }; }
这类似于Y组合器在JavaScript中的实现方式:
function y(f) { return function (a) { return f(y(f), a); }; }
你的traceSum
现在可以将功能实现为:
var traceSum = trace(function (traceSum, a) { if (a.length === 0) return 0; else return a[0] + traceSum(a.slice(1)); });
不幸的是,如果不能修改sum
函数,那么你就不能trace
因为您需要某种方式来指定要回调的函数。
考虑:
function sum(a) { if (a.length === 0) return 0; else return a[0] + sum(a.slice(1)); }
你不能trace
上面的函数是因为在函数内部sum
将始终引用函数本身。没有办法指定sum
动态的。
本质上,我们将“rec”存储在一个可变的单元格中,而不是传递它。
它会有点类似于sum = logging(sum)
(而不是sum2 =
),但它更惯用,并且不为我们发送的可变引用的名称进行硬编码。
var obj = { sum : function(a){ if (a.length === 0) { return 0; } else { return a[0] + this.sum(a.slice(1)); // <-- dispatch on `this` } } } function add_logging(obj, funcname){ var oldf = obj[funcname]; obj[funcname] = function(/**/){ console.log(arguments); return oldf.apply(this, arguments); } } add_logging(obj, 'sum');