
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 did indeed fix it. Just out of curiosity, how would I go about finding this myself? (Ideally it'd be an answer other than "read the source for the libraries you are using". :-) /M -- Magnus Therning (OpenPGP: 0xAB4DFBA4) magnus@therning.org Jabber: magnus.therning@gmail.com http://therning.org/magnus