Iteratees presuppose sequential processing. A general-purpose input method
must also support random IO: processing a seek-able input stream from an
arbitrary position, jumping back and forth through the stream. We demonstrate
random IO with iteratees, as well as reading non-textual files and converting
raw bytes into multi-byte quantities such as integers, rationals, and TIFF
dictionaries. Positioning of the input stream is evocative of delimited
continuations.

We use random and binary IO to write a general-purpose TIFF library. The
library emphasizes incremental processing, relying on iteratees and enumerators
for on-demand reading of tag values. The library extensively uses nested
streams, tacitly converting the stream of raw bytes from the file into streams
of integers, rationals and other user-friendly items. The pixel matrix is
presented as a contiguous stream, regardless of its segmentation into strips
and physical arrangement.

We show a representative application of the library: reading a sample TIFF
file, printing selected values from the TIFF dictionary, verifying the values
of selected pixels and computing the histogram of pixel values. The pixel
verification procedure stops reading the pixel matrix as soon as all specified
pixel values are verified. The histogram accumulation does read the entire
matrix, but incrementally. Neither pixel matrix processing procedure loads the
whole matrix in memory. In fact, we never read and retain more than the
IO-buffer-full of raw data.

Documentation

The type of the IO monad supporting seek requests and endianness
The seek_request is not-quite a state, more like a `communication channel'
set by the iteratee and answered by the enumerator. Since the
base monad is IO, it seems simpler to implement both endianness
and seek requests as IORef cells. Their names are grouped in a structure
RBState, which is propagated as the `environment.'

We discard all available input first.
We keep discarding the stream s until we determine that our request
has been answered:
rb_seek_set sets the state seek_req to (Just off). When the
request is answered, the state goes back to Nothing.
The above features remind one of delimited continuations.

Read n elements from a stream and apply the given iteratee to the
stream of the read elements. If the given iteratee accepted fewer
elements, we stop.
This is the variation of stake with the early termination
of processing of the outer stream once the processing of the inner stream
finished early. This variation is particularly useful for randomIO,
where we do not have to care to `drain the input stream'.