簡體   English   中英

Haskell遞歸“求和”函數

[英]Haskell Recursive 'sum' Function

我發現很難理解以下遞歸函數的機制:

sums (x:y:ys) = x:sums(x + y : ys)
sums xs = xs

sums ([0..4])

Output:
[0, 1, 3, 6, 10]

這行到底發生了什么?:

x:sums(x + y : ys)

我想說的是,在程序可以將“ x”附加到列表之前,必須先執行函數sum(x + y:ys)。 但是在那種情況下,“ x”僅會被添加到列表一次(在遞歸循環的末尾),這不會導致給定的輸出...那么我的邏輯缺陷在哪里?

我的后續問題:我應該如何以合乎邏輯的方式看待/處理遞歸函數,這將(有希望)將我引向“ aha-erlebnis”?

任何幫助深表感謝!

您可以通過逐步簡化來了解Haskell代碼。 也許下面的示例還原順序可以幫助您解決問題。

(Haskell實現實際上執行了與減少步驟相關的操作,但順序可能不同。不過,您得到的最終結果相同)。

在此示例中,您從以下內容開始:

sums [0..4]

展開[0..4]表示法:

sums (0 : 1 : [2..4])

現在我們看到的第一個方程sums相匹配,與x = 0y = 1 ,和ys = [2..4] 這樣我們得到:

0 : sums (0 + 1 : [2..4])

我們可以計算0 + 1

0 : sums (1 : [2..4])

並擴展[2..4]

0 : sums (1 : 2 : [3..4])

現在我們看到的第一等式sums再次匹配,此時用x = 1y = 2 ,和ys = [3..4] 這樣我們得到:

0 : 1 : sums (1 + 2 : [3..4])

我們可以計算1 + 2

0 : 1 : sums (3 : [3..4])

並擴展[3..4]

0 : 1 : sums (3 : 3 : [4..4])

現在我們看到的第一個方程sums再次匹配,此時x = 3y = 3 ,和ys = [4..4] 這樣我們得到:

0 : 1 : 3 : sums (3 + 3 : [4..4])

我們可以計算3 + 3

0 : 1 : 3 : sums (6 : [4..4])

並展開[4..4]

0 : 1 : 3 : sums (6 : 4 : [])

現在我們看到的第一等式sums再次相匹配,此時用x = 6y = 4 ,和ys = [] 這樣我們得到:

0 : 1 : 3 : 6 : sums (6 + 4 : [])

我們可以計算6 + 4

0 : 1 : 3 : 6 : sums (10 : [])

這次, sums的第一個方程式不匹配。 但是第二個方程匹配。 這樣我們得到:

0 : 1 : 3 : 6 : 10 : []

這是觀察到的輸出[0, 1, 3, 6, 10]

這與其他語言中的遞歸沒有什么不同。 當首先sums [0..4] (不需要括號)時, x==0y==1ys == [2..4] 因此,返回值是一個從0創建的新列表,該列表與sums [1..4]

用嚴格的語言來說,遞歸調用將在最終創建新列表之前完成。 由於Haskell是惰性的,因此將返回一個列表,該列表以0開頭,並以一個對sums [1..4]承諾繼續。 除非有人實際嘗試訪問列表的末尾,否則不會真正評估遞歸調用。

您可能會注意到

sums (x:y:ys) =  x:sums(x + y : ys)

相當於

sums (x:y:z:ys) = x:x+y:sums(x+y+z : ys)
sums (x:y:ys) = x:sums(x + y : ys)

並且(超過2個項目)也等於

sums (x:y:z: w: ys) = x:x+y:x+y+z:sums(x+y+z +w: ys)
sums (x:y:z:ys) = x:x+y:sums(x+y+z : ys)
sums (x:y:ys) = x:sums(x + y : ys)

所以通過歸納,你有

sums(1:2:3:4 :[])

等於

1 : 1 + 2 : 1 + 2 + 3 : 1 + 2 + 3 + 4 : [] 

根據以上內容,您還可以預測

fact(x:y:ys) = x: fact(x * y : ys)
fact(xs) = xs

然后

fact([1..4])

1:1*2:1*2*3:1*2*3*4:[]

有兩個方程式定義函數sums 繼續使用與參數匹配的第一個方程式或其他合適的方程式(例如1 + 2 = 3)來重寫涉及sums的表達式。

sums [0..4] = 
    -- by syntactic sugar
sums (0:1:2:3:4:[]) = 
    -- by eq. 1, x=0,y=1,ys=2:3:4:[]
0 : sums ((0+1) : 2 : 3:4:[]) = 
    -- by addition 
0 : sums (1 : 2 : 3:4:[]) = 
    -- by eq. 1, x=1, y=2, ys=3:4:[]
0 : 1 : sums ((1+2) : 3 : 4:[]) =
    -- by addition 
0 : 1 : sums (3 : 3 : 4:[]) =
    -- by eq. 1, x=3, y=3, ys=4:[]
0 : 1 : 3 : sums ((3+3) : 4 : []) = 
    -- by addition
0 : 1 : 3 : sums (6 : 4 : []) = 
    -- by eq. 1, x=6, y=4, ys=[]
0 : 1 : 3 : 6 : sums ((6+4):[]) = 
    -- by addition
0 : 1 : 3 : 6 : sums (10:[]) = 
    -- by eq  2,xs=(10:[]) 
0 : 1 : 3 : 6 : 10 : [] = 
    -- by syntactic sugar
[0,1,3,6,10]

暫無
暫無

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

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