[Haskell-cafe] compare iteratee with python's yield

Ertugrul Soeylemez es at ertes.de
Fri Jul 1 12:01:55 CEST 2011


yi huang <yi.codeplayer at gmail.com> wrote:

> I just read several tutorials on iteratee, i find that iteratee is
> similar to python's generator, both allow streamlined data
> processing. For example, i can implement enumFile and printChunks in
> python like this:
>
>     EOF = None
>     def enum_file(bufsize, filename):
>         with open(filename) as input:
>             while True:
>                 data = input.read(bufsize)
>                 if not data:
>                     break
>                 yield data
>         yield EOF
>
>     def print_chunks(print_empty, generator):
>         for chunk in generator:
>             if chunk==EOF:
>                 print 'EOF'
>                 return
>             if len(chunk)==0 and not print_empty:
>                 continue
>             print chunk
>
>     print_chunks(True, enum_file(2, "data"))
>
> But i find iteratee far more complicated than python's generator, is
> that because iteratee can do something python's generator can't, or i
> simply need to be more familar with functional programming style.

I don't know Python very well, but I suspect that its generators are
really a sort of coroutines.  Iteratees are also coroutines, but their
architecture is quite different.

The difference is that conceptually an iteratee does not know about its
input.  In Python the generator stops to wait for the iterator to
request more input:  The consumer talks to the producer.  This control
flow is turned inside out in iteratees, where the iteratee stops to wait
for the enumerator to provide more input.  The producer talks to the
consumer in iteratees.  This is a conceptual difference, so what's the
advantage?

The main advantage of iteratees, compared to generators, can be seen in
a statically typed language such as Haskell.  Let's say that instead of
printing the input lines your consumer would instead just calculate its
length and return it.  Let's call this consumer 'length'.  If you would
translate generators to Haskell, you would find that your 'length'
consumer would suddenly include a MonadIO constraint, even though it
doesn't need it.

With iteratees' inversion of control only the part which needs the
MonadIO constraint really has it.  An enumerator is really a function
from an iteratee to an iteratee.  It converts an arbitrary iteratee to
an iteratee with additional input, adding the constraints necessary to
fulfill this task.  While with the generator concept you apply a
producer to a consumer, with iteratees you apply a consumer to an
producer.

Hope that helps.


Greets,
Ertugrul


-- 
nightmare = unsafePerformIO (getWrongWife >>= sex)
http://ertes.de/





More information about the Haskell-Cafe mailing list