簡體   English   中英

這個haskell代碼如何工作?

[英]How does this haskell code work?

我是一名新生,我正在攻讀計算機科學專業。 我們正在處理Haskell,雖然我理解Haskell的想法,但我似乎無法弄清楚我們應該看到的代碼片段究竟是如何工作的:

module U1 where

double x = x + x
doubles (d:ds) = (double d):(doubles ds)
ds = doubles [1..]

我承認,對於知道發生了什么事的人來說似乎相當簡單,但我無法繞過它。 如果我寫“take 5 ds”,它顯然會回復[2,4,6,8,10]。 我沒有得到的,是為什么。

這是我的思路:我打電話給ds,然后尋找雙打。 因為我也提交了值[1 ..],雙精度(d:ds)應該表示d = 1且ds = [2 ..],對嗎? 然后我將d加倍,返回2並將其放在列表的開頭(數組?)。 然后它調用自身,將ds = [2 ..]轉換為d = 2和ds = [3 ..],然后再次將d加倍並再次調用自身,依此類推,直到它可以返回5個值, [2,4,6,8,10]。

首先,我的理解是對的嗎? 我的思緒中是否有任何嚴重的錯誤? 第二,因為它似乎將所有加倍的d保存到列表中以便稍后調用,那么該列表的名稱是什么? 我在哪里完全定義它?

在此先感謝,希望你能幫助學生理解這個x)

我認為關於doubles如何遍歷無限列表的每個元素的遞歸/循環部分你是正確的。

現在關於

它似乎將所有加倍的d保存到列表中以便稍后調用,該列表的名稱是什么? 我在哪里完全定義它?

這涉及在Haskell中稱為Lazy Evaluation的功能。 該列表未預先計算並存儲在任何位置。 相反,您可以想象列表是C ++中的一個函數對象,可以在需要時生成元素。 (您可能會看到的正常語言是表達式是按需評估的)。 所以,當你這樣做

take 5 [1..]

[1..]可以被視為一個函數對象,當與headtake等一起使用時會生成數字。所以,

take 5 [1..] == (1 :  take 4 [2..])

這里[2..]也是一個為你提供數字的“函數對象”。 同樣,你可以擁有

take 5 [1..] == (1 : 2 : take 3 [3..]) == ... (1 : 2 : 3 : 4 : 5 : take 0 [6..])

現在,我們不需要關心[6..] ,因為對於任何xs take 0 xs xs[] 因此,我們可以擁有

take 5 [1..] == (1 : 2 : 3 : 4 : 5 : [])

無需存儲任何“無限”列表,如[2..] 如果您想了解Lazy計算實際上是如何發生的,可以將它們視為函數對象/生成器。

你的思路看起來是正確的。 其中唯一的微小不准確在於使用表達式來描述計算,例如“它加倍2 然后調用自身......”。 在純函數式編程語言中,例如Haskell,實際上沒有固定的評估順序。 具體來說,在

double 1 : double [2..]

在將列表的其余部分加倍之前是否發生加倍1是未指定的。 理論結果保證了秩序確實無關緊要,因為 - 大致 - 即使你以不同的順序評估你的表達式,你也會得到相同的結果。 我建議您使用Lambda Bubble Pop網站查看此屬性:您可以按不同順序彈出氣泡以模擬任何評估順序。 無論你做什么,你都會得到相同的結果。

請注意,由於評估順序無關緊要,Haskell編譯器可以自由選擇它認為最適合您的代碼的任何評估順序。 例如,讓ds定義為代碼的最后一行,並考慮

take 5 (drop 5 ds)

這導致[12,14,16,18,20] 請注意,編譯器不需要將前5個數字加倍,因為您正在刪除它們,因此可以在完全計算之前刪除它們(!!)。

如果你想進行實驗,可以自己定義一個計算成本非常高的函數(比如,在遞歸定義后寫下fibonacci )。

fibonacci 0 = 0
fibonacci 1 = 1
fibonacci n = fibonacci (n-1) + fibonacci (n-2)

然后,定義

const5 n = 5

並計算

fibonacci 100

並觀察實際需要多長時間。 然后,評估

const5 (fibonacci 100)

並且看到結果立即到達 - 參數甚至沒有計算(!),因為不需要它。

暫無
暫無

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

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