[Haskell-cafe] Fun with the ST monad

wren ng thornton wren at freegeek.org
Sat Feb 26 03:53:19 CET 2011


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



More information about the Haskell-Cafe mailing list