
On Thu, Oct 18, 2007 at 22:58:48 +1000, Matthew Brecknell wrote:
Magnus Therning:
Still no cigar :(
Yes, this is a little more subtle than I first thought. Look at liftM and filterM:
liftM f m1 = do { x1 <- m1; return (f x1) }
filterM :: (Monad m) => (a -> m Bool) -> [a] -> m [a] filterM _ [] = return [] filterM p (x:xs) = do flg <- p x ys <- filterM p xs return (if flg then x:ys else ys)
In liftM, the result of (f x1) is not forced, and in filterM, flg is not tested until after xs is traversed. The result is that when filterM runs the (p x) action, a file is opened, but hasEmpty (and thus readFile) is not forced until all other files have likewise been opened.
It should suffice to use a more strict version of liftM:
liftM' f m1 = do { x1 <- m1; return $! f x1 }
That should also fix the problem with Jules' solution, or alternatively:
readFile' f = do s <- readFile f return $! (length s `seq` s)
Another question that came up when talking to a (much more clever) colleague was whether the introduction of either of the solutions in fact means that only a single file is open at any time? /M (I really miss IRC connectivity at work at times like this. :-) -- Magnus Therning (OpenPGP: 0xAB4DFBA4) magnus@therning.org Jabber: magnus.therning@gmail.com http://therning.org/magnus