[Haskell-cafe] Lazy counting and printing

Anakim Border akborder at gmail.com
Sat Mar 28 09:18:58 EDT 2009


I have written a code like this:

import Control.Monad.State

countedRecords        :: [Int] -> StateT Int IO [Int]
countedRecords []     = return []
countedRecords (r:rs) = do
  modify (+1)
  rest <- countedRecords rs
  return $ r:rs

printEven         :: [Int] -> StateT Int IO ()
printEven records = do
  let even = filter (\n -> n `mod` 2 == 0) records
  lift $ mapM_ (putStrLn . show) even

combine :: [Int] -> StateT Int IO ()
combine records = countedRecords records >>= printEven

main = do
   let numbers = [1..1000000]
   count <- execStateT (combine numbers) 0
   putStrLn $ "Processed " ++ show count ++ " numbers."

My intent is that of processing a large collection of records (in this
example, integers) doing two things at once: count their total number
and print those that satisfy a certain condition. I would like to keep
the definitions of the two functions performing such tasks
independent. As a result I've used the State monad to hide
intermediate counts.

Unfortunately the code above breaks laziness, in that records are
first completely counted (and stored in memory) and only then filtered
and printed. If I redefine main as:

main = do
   let numbers = [1..]

i.e. I produce an unbounded number of records, I get a stack overflow.

Moreover, I don't like the way countedRecords and printEven are
defined, because their type signatures are too "broad". I would prefer
them to be:

countedRecords :: [Int] -> State Int [Int]
printEven :: [Int] -> IO ()

and let "combine" do some sort of lifting into the StateT monad.

Is there any way to perform both operations lazily?


More information about the Haskell-Cafe mailing list