2016-09-18 58 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