On 2/25/11 2:24 PM, Andrew Coppin wrote:
I've heard much about this "iteratee" things, but I've never looked into
what the hell it actually is.

Today I had a look at TMR #16, which is an explanation which I can just
about follow. It seems that it's actually a kind of fold - not unlike
the "streams" of the stream-fusion library (which is something like what
I thought I might end up needing). It seems to handle *input* very
nicely, but I don't see much in the way of handling *output* well. (Then
again, iteratee is just too complex to really comprehend properly.)

In order to output a "stream" you want to use an "enumeratee":

    enumerator -- a "source"
        * Consumes: a standard value, e.g. a FilePath or Fd
        * Produces: a stream value

    enumeratee -- a "pipe"
        * Consumes: a stream value
        * Produces: a stream value

    iteratee -- a "sink"
        * Consumes: a stream value
        * Produces: a standard value, e.g. the sum of the stream

So when using iteratee-based methods, you'll start off with an enumerator, then have a chain of zero or more enumeratees, and then finally have the iteratee. The inputs to the enumerator and the outputs from the iteratee are just normal values.

If you're familiar with folds, then maybe you're familiar with list fusion? There are two basic kinds of list fusion: build/foldr, and unfoldr/destroy. The difference between them is just like the difference between iteratee-style streams and the standard iterator-style streams. Every time we walk over a stream/list in order to compute something, there are three steps: the production step, the consumption step, and the recursion--- the choice is how we put those three steps together. In build/foldr fusion we group the recursion with consumption (foldr); in unfoldr/destroy fusion we group the recursion step with production (unfoldr).

In the standard iterator-style we have an "iterator" which produces values on demand, and then a for-loop or similar which consumes the values and does the recursion/iteration. However, this is problematic because the iterator never knows if the for-loop will call it again, and so it doesn't know when to release resources like file handles.

In the iteratee-style, the enumerator is in charge of both production and recursion, and so it can keep forcing the iteratee to consume values until the iteratee tells the enumerator it's done. This way the enumerator knows when it's finished, and so it can release resources in a timely fashion.

Anything other than the above is implementation details which will vary depending on the implementation. Make sense?

--
Live well,
~wren

_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

Reply via email to