From: John Millikin <<a href="mailto:jmillikin@gmail.com">jmillikin@gmail.com</a>><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's my (uneducated, half-baked) two cents:<br>
<br>
There's really no need for an "Iteratee" type at all, aside from the<br>
utility of defining Functor/Monad/etc instances for it. The core type<br>
is "step", which one can define (ignoring errors) as:<br>
<br>
data Step a b = Continue (a -> Step a b)<br>
| Yield b [a]<br>
<br>
Input chunking is simply an implementation detail, but it's important<br>
that the "yield" case be allowed to contain (>= 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 -> Step a b) -> Step a b<br>
<br>
I'll leave off discussion of enumeratees, since they'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 -> 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, "Continue" has two branches. One for receiving<br>
more data, and another to be returned if there is no more input. This<br>
avoids the "divergent iteratee" problem, since it'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'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'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'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 ("What do you mean 'Result b a' doesn't have type 'Result'?")<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>
"Continue" when their inner data source runs out. Therefore, both the<br>
"continue" and "eof" parameters are Step.<br>
<br>
type Enumerator a b = (a -> Step a b) -> Step a b -> Step a b<br></blockquote><div><br>I find this unclear as well, because you've unpacked the continue parameter but not the eof. I would prefer to see this as:<br>
type Enumerator a b = (a -> Step a b) -> Result a b -> 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 -> Step a<br><br>John</div></div>