Question about the Monad instance for Iteratee (from the enumerator package)

Hello, for reference, said instance is:
instance Monad m => Monad (Iteratee a m) where return x = yield x (Chunks [])
m0 >>= f = ($ m0) $ fix $ \bind m -> Iteratee $ runIteratee m >>= \r1 -> case r1 of Continue k -> return (Continue (bind . k)) Error err -> return (Error err) Yield x (Chunks []) -> runIteratee (f x) Yield x extra -> runIteratee (f x) >>= \r2 -> case r2 of Continue k -> runIteratee (k extra) Error err -> return (Error err) Yield x' _ -> return (Yield x' extra)
The thing I don't understand yet is the last line: Why is it OK to discard the leftover input from the (f x) Iteratee and yield just the leftover input from the first one (m0)? Cheers, Daniel

2011/4/19 Daniel Schüssler
Hello,
for reference, said instance is:
instance Monad m => Monad (Iteratee a m) where return x = yield x (Chunks [])
m0 >>= f = ($ m0) $ fix $ \bind m -> Iteratee $ runIteratee m >>= \r1 -> case r1 of Continue k -> return (Continue (bind . k)) Error err -> return (Error err) Yield x (Chunks []) -> runIteratee (f x) Yield x extra -> runIteratee (f x) >>= \r2 -> case r2 of Continue k -> runIteratee (k extra) Error err -> return (Error err) Yield x' _ -> return (Yield x' extra)
The thing I don't understand yet is the last line: Why is it OK to discard the leftover input from the (f x) Iteratee and yield just the leftover input from the first one (m0)?
On that stage no input was given to (f x), we just runned it without anything and it already yielded something. So whatever it yielded must be without leftovers. Now, that's what I get from reading the code. I don't remember if it is explicitly allowed or forbidden for an iteratee to generate leftovers out of nowhere. My guess is that it doesn't make much sense to allow it. Cheers, -- Felipe.

It's forbidden for an iteratee to yield extra input that it hasn't consumed; however, this is unfortunately not enforced by the type system.

On Tue, 2011-04-19 at 10:02 -0300, Felipe Almeida Lessa wrote:
Now, that's what I get from reading the code. I don't remember if it is explicitly allowed or forbidden for an iteratee to generate leftovers out of nowhere. My guess is that it doesn't make much sense to allow it.
For the record: such code is therefore illegal abab :: Iteratee Char Identity () abab = continue parseA where parseA (Chunks ('a':'b':xs)) = parseA (Chunks xs) parseA (Chunks ('a':[])) = continue parseB parseA (Chunks xs@(_:_)) = yield () xs parseA (Chunks []) = continue parseA parseA EOF = yield () EOF parseB (Chunks ('b':xs)) = parseA (Chunks xs) parseB (Chunks xs@(_:_)) = yield () (a:xs) parseB (Chunks []) = continue parseB parseB EOF = yield () ['a'] Regards

On Fri, Apr 22, 2011 at 5:54 AM, Maciej Marcin Piechotka
For the record: such code is therefore illegal
abab :: Iteratee Char Identity () abab = continue parseA where parseA (Chunks ('a':'b':xs)) = parseA (Chunks xs) parseA (Chunks ('a':[])) = continue parseB parseA (Chunks xs@(_:_)) = yield () xs parseA (Chunks []) = continue parseA parseA EOF = yield () EOF parseB (Chunks ('b':xs)) = parseA (Chunks xs) parseB (Chunks xs@(_:_)) = yield () (a:xs) parseB (Chunks []) = continue parseB parseB EOF = yield () ['a']
Is it really illegal? I guess you're pointing out a problem with the last line, because it's EOF and we yield something. But that something was given to us in some "continue" step. IMHO, that's perfectly fine. The same thing goes for the other yield in parseB. Cheers, -- Felipe.

It's not OK and it's an artifact of the weak-typing and ill-defined semantics that pervade iteratee libraries. It's possible to do a lot of bad stuff, including binding with an iteratee yielding a remainder without consuming input. Regards, John A. De Goes Twitter: @jdegoes LinkedIn: http://linkedin.com/in/jdegoes On Apr 19, 2011, at 6:27 AM, Daniel Schüssler wrote:
Hello,
for reference, said instance is:
instance Monad m => Monad (Iteratee a m) where return x = yield x (Chunks [])
m0 >>= f = ($ m0) $ fix $ \bind m -> Iteratee $ runIteratee m >>= \r1 -> case r1 of Continue k -> return (Continue (bind . k)) Error err -> return (Error err) Yield x (Chunks []) -> runIteratee (f x) Yield x extra -> runIteratee (f x) >>= \r2 -> case r2 of Continue k -> runIteratee (k extra) Error err -> return (Error err) Yield x' _ -> return (Yield x' extra)
The thing I don't understand yet is the last line: Why is it OK to discard the leftover input from the (f x) Iteratee and yield just the leftover input from the first one (m0)?
Cheers, Daniel
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
participants (5)
-
Daniel Schüssler
-
Felipe Almeida Lessa
-
John A. De Goes
-
John Millikin
-
Maciej Marcin Piechotka