2016-09-18 61 views
1

如果我可以使用命名递归函数,应该有一种tco匿名递归函数的方法。如果有一种方法,请解释如何在下面执行此操作是我的递归函数和TCO函数。如何在ES5中对递归匿名函数应用TCO(尾部调用优化)

function recursive(length, callback) { 

    tco((function (i, sum) { 
     var args = arguments; 
     if (i > length) { 
      console.log("break statement"); 
      callback(sum) 
      return sum 
     } else { 
      return args.callee(i + 1, sum + i) 
     } 
    }))(0, 0) 
} 

function tco(f) { 
    var value; 
    var active = false; 
    var accumulated = []; 

    return function accumulator() { 
     accumulated.push(arguments); 

     if (!active) { 
      active = true; 

      while (accumulated.length) { 
       value = f.apply(this, accumulated.shift()); 
      } 

      active = false; 

      return value; 
     } 
    } 
} 
+0

我怀疑你能说出任何代码构建一个TCO(因为它是一个编译器/运行优化技术,不是你可以编码自己)。你的代码纠结了,但我猜测它只是某种奇怪的“蹦床”而已。 – zerkms

+0

你为什么认为递归需要命名函数?看看'Y'组合器。 – Bergi

+2

这与ES2015有什么关系?顺便说一句,所有的函数都已经在符合spec规范的ES6实现中进行tailrecursion优化,所以你不必自己实现任何东西。 – Bergi

回答

1

尾调用优化的

ES6提出更改尾呼叫系统,发动机优化。尾部调用是当一个函数被称为在另一个函数的最后一条语句,像这样:

function doSomething() { 
    return doSomethingElse(); // tail call 
} 

的ECMAScript 6旨在减少某些尾调用堆栈的大小要求严格的模式。有了这种优化,,而不是创造一个尾调用一个新的堆栈帧,当前栈帧被清除,只要满足以下条件重用:

  1. 严格模式必须开启。
  2. 尾调用不需要访问当前栈帧中的变量(意思是函数不是闭包)。
  3. 尾部调用返回后,进行尾部调用的函数没有其他工作要做。
  4. 尾调用的结果作为函数值返回。

也许最难避免的情况是使用闭包。由于闭包可以访问包含范围内的变量,所以可以关闭尾部呼叫优化。例如:

"use strict"; 

function doSomething() { 
    var num = 1, 
     func =() => num; 

    // not optimized - function is a closure 
    return func(); 
} 

线束的TCO优化:

考虑这个功能,它计算阶乘:

"use strict"; 
function factorial(n) { 

    if (n <= 1) { 
     return 1; 
    } else { 

     // not optimized - must multiply after returning 
     return n * factorial(n - 1); 
    } 
} 

为了优化功能,你需要确保乘法在最后一次函数调用后不会发生。

"use strict"; 
function factorial(n, p = 1) { 

    if (n <= 1) { 
     return 1 * p; 
    } else { 
     let result = n * p; 

     // optimized 
     return factorial(n - 1, result); 
    } 
} 

来源:真棒书尼古拉斯Zakas,理解的ECMAScript 6

+0

我不知道为什么关闭会阻止tco,是否有任何理由?我不认为这是规范 - tco应该总是会发生。上下文需要保留,直到封闭不再使用它并不意味着堆栈框架需要留下来。 – Bergi

+0

闭包的自由变量存储在堆中。因此封闭体可以比它周围的范围长寿命。因此,关闭不会影响TCO。 – ftor

+0

我确实检查了规范,没有发现有关闭包的信息,我的回复来自Nicholas Zakas的书,因此我向他询问了这个问题,希望我能得到答复并更新。 – Bamieh