Haskell has some great solutions for lazy IO: io-streams or pipes for example. Check them out! It's a great way to code IO.
I thought conduits and io-streams are preferred over pipes.
1. Pipes | Conduit
2. io-streams (perhaps not in 1 only because of a lack of popularity and it is new)
3. Iteratees (have some issue Pipes/Conduit do not which I can't recall)
Not sure where Machines comes in here.