我是一位Haskell新手,他在理解seq
時遇到了問題,我在下面的示例中對此進行了總結。瞭解Haskell seq
下面是相同(傻)功能的2個實現。該函數採用正整數n並返回元組(n,n)
。答案是通過使用具有元組累加器的輔助函數從(0,0)
開始計數而產生的。爲了避免構建一個大型的thunk,我使用seq來使得累加器嚴格。
在testSeq1
元組的內容是嚴格的,而在testSeq2
元組本身是嚴格的。我認爲這兩個實現將具有相同的性能。但實際上testSeq1
的'使用總內存'僅爲1MB,而testSeq2
(當使用n = 1000000進行測試時)爲187MB。
testSeq2
有什麼問題?
testSeq1 :: Int -> (Int,Int)
testSeq1 n = impl n (0,0) where
impl 0 (a,b) = (a,b)
impl i (a,b) = seq a $ seq b $ impl (i-1) (a+1, b+1)
testSeq2 :: Int -> (Int,Int)
testSeq2 n = impl n (0,0) where
impl 0 acc = acc
impl i acc = seq acc $ impl (i-1) ((fst acc)+1, (snd acc)+1)
對於元組構造函數來說,這是一種特殊的處理方法,還是你說對任何構造函數的參數都不會發生評估?假設我創建了自己的元組數據類型,而不是使用內置的元組,結果會是一樣的嗎? – BillyBadBoy
這不是特殊的元組;發生這種情況是因爲Haskell是懶惰的,只會根據需要進行評估。你可以用'Just undefined'或者你自己的數據類型做類似的例子來測試。 – Tordek
這對我來說很震驚。我認爲seq的全部重點是能夠覆蓋Haskell的默認「懶惰」並迫使它完全評估一個表達式。這解釋了爲什麼我嘗試使用foldl'沒有按照我的預期工作 - 我在我的累加器函數中使用了元組構造函數。 – BillyBadBoy