递归函数的高阶函数?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (12)

是否有某种方法可以通过高阶函数“包装”递归函数,从而使递归调用也被包装?

例如,假设我们有一个函数,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');

扫码关注云+社区