From: John Millikin &lt;<a href="mailto:jmillikin@gmail.com">jmillikin@gmail.com</a>&gt;<br><div class="gmail_quote"><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">

<br>
Here&#39;s my (uneducated, half-baked) two cents:<br>
<br>
There&#39;s really no need for an &quot;Iteratee&quot; type at all, aside from the<br>
utility of defining Functor/Monad/etc instances for it. The core type<br>
is &quot;step&quot;, which one can define (ignoring errors) as:<br>
<br>
    data Step a b = Continue (a -&gt; Step a b)<br>
                  | Yield b [a]<br>
<br>
Input chunking is simply an implementation detail, but it&#39;s important<br>
that the &quot;yield&quot; case be allowed to contain (&gt;= 0) inputs. This allows<br>
steps to consume multiple values before deciding what to generate.<br>
<br>
In this representation, enumerators are functions from a Continue to a Step.<br>
<br>
    type Enumerator a b = (a -&gt; Step a b) -&gt; Step a b<br>
<br>
I&#39;ll leave off discussion of enumeratees, since they&#39;re just a<br>
specialised type of enumerator.<br>
<br>
-------------<br>
<br>
Things become a bit more complicated when error handling is added.<br>
Specifically, steps must have some response to EOF:<br>
<br>
    data Step a b = Continue (a -&gt; Step a b) (Result a b)<br>
                  | Result a b<br>
<br>
    data Result a b = Yield b [a]<br>
                    | Error String<br>
<br>
In this representation, &quot;Continue&quot; has two branches. One for receiving<br>
more data, and another to be returned if there is no more input. This<br>
avoids the &quot;divergent iteratee&quot; problem, since it&#39;s not possible for<br>
Continue to be returned in response to EOF.<br></blockquote><div><br>Is this really true?  Consider iteratees that don&#39;t have a sensible default value (e.g. head) and an empty stream.  You could argue that they should really return a Maybe, but then they wouldn&#39;t be divergent in other formulations either.  Although I do find it interesting that EOF is no longer part of the stream at all.  That may open up some possibilities.<br>
<br>Also, I found this confusing because you&#39;re using Result as a data constructor for the Step type, but also as a separate type constructor.  I expect this could lead to very confusing error messages (&quot;What do you mean &#39;Result b a&#39; doesn&#39;t have type &#39;Result&#39;?&quot;)<br>
 <br></div><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
<br>
Enumerators are similarly modified, except they are allowed to return<br>
&quot;Continue&quot; when their inner data source runs out. Therefore, both the<br>
&quot;continue&quot; and &quot;eof&quot; parameters are Step.<br>
<br>
    type Enumerator a b = (a -&gt; Step a b) -&gt; Step a b -&gt; Step a b<br></blockquote><div><br>I find this unclear as well, because you&#39;ve unpacked the continue parameter but not the eof.  I would prefer to see this as:<br>
    type Enumerator a b = (a -&gt; Step a b) -&gt; Result a b -&gt; Step a b<br><br>However, is it useful to do so?  That is, would there ever be a case where you would want to use branches from separate iteratees?  If not, then why bother unpacking instead of just using<br>
    type Enumerator a b = Step a b -&gt; Step a<br><br>John</div></div>