【问题标题】:How to modify this code to enable tail call optimization in ES6?如何修改此代码以在 ES6 中启用尾调用优化?
【发布时间】:2015-04-15 14:10:26
【问题描述】:

我写了一个函数来递归地求和值,但它不符合 ES6 中尾调用优化的标准(原因我无法表达)。

function sum(...values) {
  if(!values.length) { 
    return 0; 
  }
  return values.shift() + sum(...values);
}

如何将其更改为符合优化条件?

【问题讨论】:

  • 执行此操作的一般方法是传递某种类型的累加器参数。就我个人而言,我只会声明一个带有额外参数的本地函数;我会举个例子,但我还不擅长 ES6 语法:)
  • 哈哈,我输入的函数几乎与 Bergi 的答案一模一样,但我认为它可能是错误的。
  • 我认为这不应该被关闭。它在局部类似于链接的问题,但这是关于 JavaScript 的,是一个很好的例子。

标签: javascript recursion ecmascript-6 tail-call-optimization


【解决方案1】:

你需要做的

return sum(…);

制作一个正确的tail call。在您的示例中,+ 操作仍然在递归调用之后执行,这使得它不起作用。

典型的做法是使用带有累加器参数的辅助函数:

 function sum(...values) {
     function sumTo(acc, values) {
         if (!values.length) return acc;
         else return sumTo(acc+values.shift(), values); // tail-recursive call
     }
     return sumTo(0, values);
 }

在对列表进行递归时,您还可以(ab)使用列表本身:

function sum(...values) {
    switch (values.length) {
        case 0:  return 0;
        case 1:  return values[0];
        default: values.unshift(values.shift()+values.shift());
                 return sum(...values);
    }
}
// or alternatively:
function sum(acc, ...values) {
    switch (arguments.length) {
        case 0:  return 0;
        case 1:  return acc;
        default: values[0] += acc;
                 return sum(...values);
    }
}

【讨论】:

  • 是的——但这真的是你调用带有数组参数的. . . 函数的方式吗?我还没有使用过 ES6 的东西。
  • @Pointy:sum !== sumTosum 在本例中从未被调用。
  • @FelixKling 是的,但是......哦,我明白了。啊,呵呵,有道理。已经是一个数组了。
  • @Pointy:我应该使用... 来代替sumTo 以使其更清晰吗?我不确定。
  • @Bergi 不,我认为这很好;我只是感到困惑。我认为(如果您使用 ...)您需要使用 .apply() 调用它,这会有点混乱,不是吗?
猜你喜欢
  • 2017-12-21
  • 2011-04-09
  • 1970-01-01
  • 2018-03-30
  • 2011-06-24
  • 1970-01-01
  • 1970-01-01
  • 2015-07-20
  • 1970-01-01
相关资源
最近更新 更多