2016-01-22 82 views
3

我在理解Haskell懶惰評估時遇到困難。困惑:Haskell IO懶惰

我寫了簡單的測試程序。它讀取4行數據,並且 第二和第四輸入行有很多數字。

consumeList :: [Int] -> [Int] -> [Int] 
consumeList [] _ = error "hi" -- to generate heap debug 
consumeList (x:xs) y = consumeList xs y 
main = do 
    inputdata <- getContents 
    let (x:y:z:k:xs) = lines inputdata 
     s = map (read ::String->Int) $ words $ k 
     t = [] 
    print $ consumeList s t 

wordsmap上的字符流執行 懶惰地,該程序使用常數存儲器。 constant memory usage

但是,當我添加論據t,情況發生了變化。 我的期望是因爲tmapwords懶惰流, 和tconsumeList使用,這種變化應該不會改變 內存使用情況。但不是。

consumeList :: [Int] -> [Int] -> [Int] 
consumeList [] _ = error "hi" -- to generate heap debug 
consumeList (x:xs) y = consumeList xs y 
main = do 
    inputdata <- getContents 
    let (x:y:z:k:xs) = lines inputdata 
     s = map (read ::String->Int) $ words $ k 
     t = map (read ::String->Int) $ words $ y 
    print $ consumeList s t -- <-- t is not used 

memory is increasing

Q1)爲什麼這個計劃一直在t完全不使用的內存分配?

我還有一個問題。當我與[,]模式匹配延遲流,而不是 與(:)內存分配行爲已更改。

consumeList :: [Int] -> [Int] -> [Int] 
consumeList [] _ = error "hi" -- to generate heap debug 
consumeList (x:xs) y = consumeList xs y 
main = do 
    inputdata <- getContents 
    let [x,y,z,k] = lines inputdata -- <---- changed from (x:y:..) 
     s = map (read ::String->Int) $ words $ k 
     t = [] 
    print $ consumeList s t 

memory keeps increasing

Q2)是(:)和懶惰evalutation方面[,]不同?

歡迎任何評論。感謝

[編輯]

Q3)然後,是否有可能處理第四行第一和 處理第二行,而無需增加內存消耗?

Derek指導的實驗如下。 從第二個例子開關Y,K的,我得到了相同的結果:

consumeList :: [Int] -> [Int] -> [Int] 
consumeList [] _ = error "hi" 
consumeList (x:xs) y = consumeList xs y 
main = do 
    inputdata <- getContents 
    let (x:y:z:k:xs) = lines inputdata 
     s = map (read ::String->Int) $ words $ y -- <- swap with k 
     t = map (read ::String->Int) $ words $ k -- <- swap with y 
    print $ consumeList s t 

enter image description here

回答

5

要回答你的第一個問題,t,直到你達到終點就住因爲垃圾收集關注consumeList。這並不是什麼大不了的事情,因爲t會是一個指向工作的熱門話題,但問題在於,現在這個問題是:現在保持y活着,而getContents必須在y中實際讀取到k。在你的第一個例子中,y在讀入時可能被垃圾收集。(作爲一個實驗,如果你在本例中切換了yk,我懷疑你會看到與第一個例子非常相似的行爲。)

對於第二個問題,let [x,y,z,k] = ...的意思是「(無可辯駁地)匹配的列表,正好是四個元素」。這意味着當你強制k它需要(在這一點上)檢查沒有更多的元素,這意味着它需要讀取對應於k的所有輸入,然後才能開始處理它。在之前的情況下,let (x:y:z:k:xs) = ...它可以立即開始處理k,因爲它不必首先檢查xs是否爲[](_:_)

+0

我已經有點了解了。謝謝。你會回答我一些更多的任務嗎? (1)那麼是否可以處理第4行然後處理第2行而不增加內存消耗?如果僅僅從'(x:y:z:k:xs)'持有'y'的指針強制讀取和處理流,是不可能的? (2)圖表''ghc-prim.GHC.Types:'表示由'getContents'讀取的原始字符串或由'map處理的列表。 words'?我看到的內存量爲〜100MB,但實際輸入數據爲5MB。所以,我懷疑分配的內存可能是'map。單詞'處理一個。 –

+0

也許你應該開始提出新的問題 - 但通常在這種情況下離開懶惰IO是一個好主意(正如你所看到的,有時候會有點痛苦) – Carsten

+0

我明白了。我將針對上述評論的第一個問題開始一個新問題。 –