These things are always tricky to understand, which is why I recommend not using lazy I/O. File reading is not a pure operation: running out of file descriptors is a good counter-example.
Without saying wether I agree with lazy I/O or not, I suggest that this particular problem may also be due to the runtime implementation: If one tries to open a new file but the file descriptors are exhausted, the runtime system should first trigger a full GC because that might free up some descriptors -- but maybe GHC is already doing this?
GHC could do this, but it doesn't. Nevertheless, it wouldn't help in Ketil's example: no amount of GC is going to free up the file descriptors which are being held on to because the program hasn't completely evaluated the file contents yet. Cheers, Simon