簡體   English   中英

Haskell無限遞歸

[英]Haskell infinite recursion

以下函數計算Fibonacci序列:

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

如果我們運行它,我們將得到一個無限列表,但遞歸如何工作? 如果該功能一直在調用,為什么它會在屏幕上打印數字呢? 如果您能解釋編譯器如何管理調用,我將不勝感激。

我畫了一張你可能覺得有幫助的照片。
請注意, zipWtih op (x:xs) (y:xs) = (op xy):zipWith xs ys ,這就是zipWtih在列表中“向右移動”的方式。 它是讀取元素並吐出總和:

pic用彩色指針


這是一個更詳細的逐步評估。 (雖然我會粘貼那些內容的副本,但內存中只有一個副本。)我會使用....因為我不能寫出來的東西。

fib = 0:1:zipWith (+) fib (tail fib)
    = 0:1:zipWith (+) (0:1: .... ) (tail (0:1: .... )
    = 0:1:(0+1:zipWith (+) (1:(0+1: .... )) ( 0+1:..... ))
    = 0:1:1:zipWith (+) (1: ....) (......)

注意,現在我們知道zipWith (+) fib (tail fib) = 1:.....

    = 0:1:1:zipWith (+) (1:1: ....) (1:......)
    = 0:1:1:(1+1):zipWith (+) (1:(1+1): .....) ((1+1):....)
    = 0:1:1:2:zipWith (+) (1:2: .....) (2:....)

我會快一點:

    = 0:1:1:2:(1+2):zipWith (+) (2: .....) (....)
    = 0:1:1:2:3     :zipWith (+) (2:3 .....) (3:....)
    = 0:1:1:2:3:(2+3):zipWith (+) (3:(2+3):.....) ((2+3):.....)
    = 0:1:1:2:3:5     :zipWith (+) (3:5:.....) (5:.....)
    = 0:1:1:2:3:5:8    :zipWith (+) (5:8:....) (8:......)
    = 0:1:1:2:3:5:8:13  :zipWith (+) (8:13:....) (13:......)
    = 0:1:1:2:3:5:8:13:21:zipWith (+) (13:21....) (21:......)

在每個階段, zipWith函數的最后兩個參數就像指向(一個和兩個位置)的指針,它們在fib列表中比我們目前更進一步。

總之一句話:懶惰。 Haskell中的列表更像是一個生成器:它只會在其他東西需要時計算值。

例如, head [1 , 2+3]將不執行添加,因為不需要。 類似地,如果我們遞歸地讓ones = 1 : ones ,那么head ones = head (1 : ones) = 1不需要評估所有尾部。

您可以嘗試猜測如果我們打印一對x會發生什么,定義如下:

x = (n, fst x + 1)

上面我們使用(懶)對而不是(懶)列表,但推理是相同的。 除非其他東西需要,否則不要評估任何東西。

暫無
暫無

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

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