Haskell の遅延評価を理解するのに苦労しています。
簡単なテストプログラムを書きました。4行のデータを読み取り、2番目と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
words
map
文字のストリームに対して遅延して実行されるため、このプログラムは一定のメモリを使用します
。
しかし、引数を追加するとt
、状況が変わります。私の期待は、t
およびmap
遅延words
ストリーム上であり、 でt
使用されていないためconsumeList
、この変更によりメモリ使用量が変更されることはありません。しかし、いいえ。
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
t
Q1)まったく使用されていないのに、このプログラムがメモリを割り当て続けるのはなぜですか?
別の質問があります。レイジー ストリームをパターン マッチさせると[,]
、(:)
メモリ割り当ての動作が変更されます。
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
Q2)(:)
と[,]
は遅延評価の点で異なりますか?
どんなコメントでも大歓迎です。ありがとう
[編集]
Q3) では、メモリ消費を増やさずに、4 行目を先に処理し、2 行目を処理することは可能でしょうか?
Derek が案内する実験は次のとおりです。2 番目の例から 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