seq / strictness and laziness

Amanda Clare ajc99@aber.ac.uk
Mon, 12 Nov 2001 15:43:08 +0000


I have some code which is being unnecessarily lazy (and occupying too
much heap space). The code should read and process several files one by
one. What's happening is that all files get read in but the processing
is delayed by laziness, and the files are being retained. It looks
something like this (after simplification):

main = do
          result <- foldM countAFile initialcounts fileNameList
          prettyprint result

countAFile oldcounts filename =
    do 
        compiledFile <- readAndCompile filename
        let newcounts = countAssociations compiledFile oldcounts
        return newcounts


I would love to have used CPS, but this seems to force me to lift a huge
amount of code into both the IO monad and the CPS, as countAssociations
just calls another function, which calls another, and so on. 

If I change countAFile to use a redundant test to force evaluation of
newcounts:

countAFile oldcounts filename =
    do 
        compiledFile <- readAndCompile filename
        let newcounts = countAssociations compiledFile oldcounts
        if newcounts == newcounts 
           then return newcounts
           else error "suitable error message"

then the program runs beautifully (if a little slowly), occupying a
constant amount of heap.

If instead I use a strict data type to store my counts, or use seq, then
I get no improvement, and it's just as if I hadn't used them. I
understand why a strict data type won't help me, as it's the function
calls that are lazy. But what about $! and seq?

countAFile oldcounts filename =
    do 
        compiledFile <- readAndCompile filename
        let newcounts = countAssociations compiledFile oldcounts
	return $! newcounts

Does anyone understand why $! (or equivalently "seq") have no effect
here? Is there a better way to do this?

Amanda
--
Amanda Clare  http://users.aber.ac.uk/ajc99/
Tel: +44 (0)1970 621922  Fax: +44 (0)1970 622455
Dept. of Computer Science, University of Wales, Aberystwyth, SY23 3DB