[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