Смущенный: Haskell IO Laziness

У меня возникают трудности в понимании ленивых оценок Хаскелла.

Я написал простую тестовую программу. Он читает 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

память увеличивается

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

память продолжает расти

Q2) являются (:) а также [,] отличается с точки зрения ленивой оценки?

Любые комментарии приветствуются. Спасибо

[РЕДАКТИРОВАТЬ]

В3) Тогда можно ли обрабатывать 4-ю строку первой, а 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

введите описание изображения здесь

1 ответ

Решение

Чтобы ответить на ваш первый вопрос, t жив, насколько сборщик мусора обеспокоен, пока вы не достигнете конца consumeList, Это не было бы таким большим делом, так как t было бы громогласным указателем на работу, но проблема здесь в том, что громогласный теперь держит y жив и getContents должен на самом деле читать в y чтобы добраться до k, В вашем первом примере y может быть сборка мусора во время чтения. (Как эксперимент, если вы переключились y а также k в этом примере я подозреваю, что вы увидите поведение, очень похожее на ваш первый пример.)

На ваш второй вопрос let [x,y,z,k] = ... означает "(неопровержимо) сопоставить список ровно из четырех элементов". Это означает, что когда вы заставляете k он должен (на этом этапе) проверить, что больше нет элементов, что означает, что он должен прочитать все входные данные, соответствующие k прежде чем он может начать обрабатывать его. В предыдущем случае let (x:y:z:k:xs) = ... он может начать обработку k немедленно, потому что не нужно сначала проверять, xs является [] или же (_:_),

Другие вопросы по тегам