簡體   English   中英

有關“尾叫優化”文章的問題

[英]Question on “Tail Call Optimization” Article

我對這篇文章有疑問。

這段代碼之間

function odds(n, p) {
  if(n == 0) {
    return 1
  } else {
    return (n / p) * odds(n - 1, p - 1)
  }
}

和這段代碼

(function(){
  var odds1 = function(n, p, acc) {
    if(n == 0) {
      return acc
    } else {
      return odds1(n - 1, p - 1, (n / p) * acc)
    }
  }

  odds = function(n, p) {
    return odds1(n, p, 1)
  }  
})()

1)我對此有多大困惑。 第二個代碼段是否只是簡單地進行了尾部調用,因為它可以在再次調用自身之前計算出所需的內容,從而減少了開銷,還是我還缺少更多的功能?

據我了解,尾調用仍然沒有消除,只是優化了。

2)為什么不應該有一定oddsodds1呢? 我還是不清楚。

我對這有多大幫助感到困惑。 第二個代碼段是否只是簡單地進行了尾部調用,因為它可以在再次調用自身之前計算出所需的內容,從而減少了開銷,還是我還缺少更多的功能?

據我了解,尾調用仍然沒有消除,只是優化了。

如果過程結束看起來像這樣:

push args
call foo
return

然后編譯器可以將其優化為

jump startOfFoo

完全消除過程調用。

為什么仍然需要幾率? 我還是不清楚。

odds的“合同”僅指定兩個參數-第三個參數僅是實現細節。 因此,您可以將其隱藏在內部方法中,並提供“包裝器”作為外部API。

你可以稱之為odds1oddsImpl ,它會更清楚,我想。

第一個版本不是尾部遞歸,因為在獲得odds(n - 1, p - 1)的值之后odds(n - 1, p - 1)它必須將其乘以(n / p) ,第二個版本將其移到參數的計算中函數odds1使它正確地尾部遞歸。

如果您查看調用堆棧,則第一個調用將如下所示:

odds(2, 3)
  odds(1, 2)
    odds(0, 1)
    return 1
  return 1/2 * 1
return 2/3 * 1/2

而第二個是:

odds(2, 3)
  odds1(2, 3, 1)
    odds1(1, 2, 2/3)
      odds1(0, 1, 1/2 * 2/3)
      return 1/3
    return 1/3
  return 1/3
return 1/3

因為您只是返回遞歸調用的值,所以編譯器可以輕松優化此值:

odds(2, 3)
#discard stackframe
odds1(2, 3, 1)
#discard stackframe
odds1(1, 2, 2/3)
#discard stackframe
odds1(0, 1, 1/3)
return 1/3

具有oddsodds1的原因odds1是在其他代碼調用此函數時提供初始累加器值。

尾遞歸的優化如下,在第一個示例中,因為直到調用odds(n-1),您才能計算乘法return (n / p) * odds(n - 1, p - 1)的結果return (n / p) * odds(n - 1, p - 1) -1) ,操作者必須將我們當前的位置保存在內存中(在堆棧上),並打開一個新的賠率電話。

遞歸地,這也將在下一個調用中以及隨后的調用中發生,依此類推。 因此,到遞歸結束並開始返回值並計算乘積時,我們將有n個待處理操作。

在第二個示例中,由於執行的return語句只是return odds1(n - 1, p - 1, (n / p) * acc)我們可以計算函數參數,而無需保持就可以簡單地調用odds1(n-1) 我們目前的職位 這就是優化所在,因為現在我不必每次在堆棧上打開新框架時都記得自己在哪里。

可以將其視為書籍參考。 想象您打開一本食譜並轉到某個食譜,其食材如下所示:

  1. 下一頁的成分

下一頁有

  1. 胡椒
  2. 下一頁的成分

等等。你怎么知道所有成分是什么? 您必須記住在每一頁上看到的內容!

盡管第二個示例更像以下成分列表:

  1. 忘記這一點,只需使用下一頁上的內容即可

下一頁有:

  1. 胡椒
  2. 忘記這一點,只需使用下一頁上的內容即可

等等。等到到達最后一頁時(注意,類推是准確的,因為兩者都調用相同數量的函數),您便擁有了所有要素,而不必“保留在內存中”在每一頁上看到的內容,因為所有內容都在最后一頁!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM