3

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

wordsmap文字のストリームに対して遅延して実行されるため、このプログラムは一定のメモリを使用します 。一定のメモリ使用量

しかし、引数を追加すると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

記憶力が上がる

tQ1)まったく使用されていないのに、このプログラムがメモリを割り当て続けるのはなぜですか?

別の質問があります。レイジー ストリームをパターン マッチさせると[,](:)メモリ割り当ての動作が変更されます。

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

ここに画像の説明を入力

4

1 に答える 1

5

最初の質問に答えるにtは、ガベージ コレクターに関する限り、consumeList. サンクが仕事を指しているので、それはそれほど大したことではありませんtが、ここでの問題は、サンクが現在もy生き続けており、に到達するためgetContentsに実際に読み込む必要があるyことkです。最初の例でyは、読み込まれているときにガベージ コレクションが行われる可能性がありyますk

2番目の質問では、「(反論の余地なく)正確に4つの要素let [x,y,z,k] = ...のリストに一致する」ことを意味します。つまり、強制すると、(その時点で) それ以上の要素がないことを確認する必要があります。つまり、処理を開始する前に、対応するすべての入力を読み込む必要があります。前のケースでは、最初にisかかどうかをチェックする必要がないため、すぐに処理を開始できます。kklet (x:y:z:k:xs) = ...kxs[](_:_)

于 2016-01-22T05:20:38.033 に答える