
On Wed, Aug 25, 2010 at 01:33, John Lato
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.
Divergent iteratees, using the current libraries, will simply throw an exception like "enumEOF: divergent iteratee". There's no way to get useful values out of them. Disallowing returning Continue when given an EOF prevents this invalid state.
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'?")
Oh, sorry, those constructors should be something like this (the system on which I wrote that email has no Haskell compiler, so I couldn't verify types before sending): data Step a b = Continue (a -> Step a b) (Result a b) | GotResult (Result a b) The goal is to let the iteratee signal three states: * Can accept more input, but terminating the stream now is acceptable * Requires more input, and terminating the stream now is an error * Cannot accept more input
I find this unclear as well, because you've unpacked the continue parameter but not the eof. I would prefer to see this as: type Enumerator a b = (a -> Step a b) -> Result a b -> Step a b
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 type Enumerator a b = Step a b -> Step a
When an enumerator terminates, it needs to pass control to the next enumerator (the final enumerator is enumEOF). Thus, the second "step" parameter is actually the next enumerator to run in the chain (aka the calling enumerator).