2011-05-05 25 views
15

在具有懶惰語義的純功能性的語言(如Haskell中),計算的結果被memoized使得具有相同的輸入的功能的進一步的評估不重新計算的值而是直接從memoized值的高速緩存得到它。像Haskell這樣的函數式語言中,memoized值的生命期是多少?

我想知道如果這些memoized值獲得在某個時間點回收?

  1. 如果是這樣,則意味着memoized值必須在稍後的時間重新計算,並記憶化的好處是不那麼退出恕我直言。
  2. 如果沒有,那麼OK,這是聰明的緩存的一切......但它意味着一個程序 - 如果運行時間足夠長一段 - 將 總是消耗越來越多的內存?

想象一個程序執行密集的數值分析:例如,要查找的使用二分法算法幾千幾百數學函數列表的根。

每次節目評估與特定的實數的數學函數,結果將被memoized。但是,只有一個非常小的概率 是完全一樣的實數將在算法中再次出現,導致內存泄露(或至少,真的不好的用法)。

我的想法是,也許memoized的值只是「作用域」的程序中的某些東西(例如對當前的延續,調用堆棧等),但我無法找到有關該主題的實用內容。

我承認我沒有在Haskell編譯執行深深的看了(懶惰?),但請,可能有人向我解釋,在實踐中是如何工作的?


編輯:好吧,我明白了從最初的幾個回答我的錯誤:純語義意味着引用透明而這又並不意味着自動記憶化,而只是保證會有它沒有問題。

我認爲網上的一些文章會誤導這件事,因爲從初學者的角度來看,參考透明屬性看起來很酷,因爲它允許隱式記憶。

+0

查看http://stackoverflow.com/questions/3951012/when-is-memoization-automatic-in-ghc-haskell – 2011-05-22 16:11:36

回答

19

Haskell確實不是自動記憶函數調用,正是因爲這會快速消耗大量內存。如果你自己做記憶,你可以選擇記憶功能的範圍。例如,假設你有一個這樣定義的斐波那契功能:

fib n = fibs !! n 
    where fibs = 0 : 1 : zipWith (+) fibs (tail fibs) 

在這裏,記憶化只是一個通話中做fib,而如果你在頂層

fib n = fibs !! n 

fibs = 0 : 1 : zipWith (+) fibs (tail fibs) 

離開fibs然後備忘錄列表會一直保留,直到垃圾收集器可以確定沒有其他方法可以從程序的任何部分到達fibs

+0

+1對於這個暗示性的例子 - 雖然我敢打賭,在這種情況下*實際上*編譯器會看到fibs並不需要是一個本地值,並將其提升到最高層。 – Ingo 2011-05-05 13:45:55

+2

@Ingo:我的印象是,編譯器_並沒有讓一個lambda外的任何東西浮動,正是因爲這會對內存使用產生重大影響,但我可能是錯的。 – hammar 2011-05-05 13:57:16

+0

@ngo:似乎有一個優化稱爲_full懶惰_這是做到這一點,但我不確定它是否適用於這種情況。 – hammar 2011-05-05 14:19:58

4

我的想法是,也許memoized值只是「作用域」的程序中的東西(例如對當前的延續,調用堆棧等)。),但我無法找到關於這個問題的實際情況。

這是正確的。特別是,當你看到這樣:

fun x y = let 
    a = ..... 
    b = .... 
    c = .... 
in .... 

或等效的where子句中,值A,B和C可能沒有被計算到實際使用(或者也可以馬上計算,因爲嚴格分析儀可以坡口說無論如何,這些值將被評估)。但是,當這些值取決於當前函數參數(這裏是x和y)時,運行時很可能不會記住x和y以及由此產生的a,b和c的每個組合。

還要注意,在純語言中,根本不記得這些值也是可以的 - 這隻有在內存比CPU時間便宜時才實用。

所以你的問題的答案是:沒有這樣的事情在Haskell中間結果的生命。所有人可以說的是,評估的價值將在需要時在那裏。

相關問題