I'm having difficulties in understanding Haskell lazy evaluation.
I wrote simple test program. It reads 4 lines of data and second and fourth input line has lots of numbers.
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
and map
is performed
on streams of characters lazily, this program use constant memory.
But As I add arguments t
, situation is changed.
My expectation is since t
is map
and words
on lazy stream,
and t
is not used in consumeList
, this change should not alter
memory usage. But no.
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) Why does this program keeps allocating memory when t
is not used at all?
I have another question. When I pattern match lazy stream with [,]
, not
with (:)
memory allocation behaviour is changed.
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) are (:)
and [,]
different in terms of lazy evalutation?
Any comments are welcomed. Thanks
[EDIT]
Q3) Then, is it possible to process 4th line first and the process 2nd line, without increasing memory consumption?
The experiment guided by Derek is as follows. With switching y and k from second example, I got same result:
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