[Agda] IO, semi-closed handles, and problems with extensional equality

Alan Jeffrey ajeffrey at bell-labs.com
Wed Oct 6 16:29:30 CEST 2010


On 10/05/2010 09:40 PM, wren ng thornton wrote:
> You can't. Or rather, you can't for all possible transformXML without
> breaking the nice resource guarantees that iteratees give you. The proof
> is trivial. The idea of iteratees is based around stream processing; so
> long as you can process the stream incrementally (as you can with `wc`
> and most parsers), then you can produce output with fixed overhead. But
> streams don't support random access or unbounded scanning, so there are
> transformations of sequences which can't but hold onto the entire
> sequence before generating output (or alternatively, re-reading the
> inputs). But that problem isn't anything new: if you need the whole file
> in memory, that's your problem :)

Indeed.  I suspect that there is a hack with callcc that could do the 
trick, and would give O(height) space usage in the case where 
transformXML implements a tree automaton, but it wouldn't be pleasant!

> But, there are other resource guarantees that iteratees give besides
> memory consumption. The most important ones are that it gives you
> control over when resources like filehandles, sockets, and database
> connections are acquired and released. It's these resources which cause
> the big bugs with lazy-IO, and they're far more precious than memory. So
> long as your transformXML function can consume its entire input in a
> timely fashion, we can still guarantee that the filehandle is released
> in a timely fashion. No semi-closed filehandle nonsense.

Indeed.  That's what I'm hoping for over at:

   http://github.com/agda/agda-system-io

The idea is that "commit" guarantees a point at which resources are 
released, so the XML example becomes:

   getContents >>= \x ->
   let xml = parseXML x in
   let xml' = transformXML xml in
   putStr (serializeXML xml') >>
   commit

and it's that final commit that forces the IO to take place, after which 
the input stream is guaranteed to be closed.  Moreover, you can add 
extra commit points if you want more strictness, e.g. to force all XML 
parsing to take place before transformation, you say:

   getContents >>= \x ->
   let xml = parseXML x in
   commit >>
   let xml' = transformXML xml in
   putStr (serializeXML xml') >>
   commit

There's lots of rough edges here though, notably a lack of ACID 
guarantees (not much we can do about that in the absence of a 
transactional filesystem), and lack of rollback or exception handling.

A.


More information about the Agda mailing list