Iteratee rest and monad instance

I've mostly been studying the Iteratee IO slides (with notes), so these things may already have been noted elsewhere (though I have not been able to find them with my cursory search). Also excuse my probably somewhat confused terminology, I hope I get the point across anyway. In both the slides and the current hackage package "finished" iteratees carry with them (in the constructor) the rest of the stream. I may miss something obvious here, but this seems to lead to some fishy details in the monad instance of iteratees presented in the slides. Firstly the iteratee given by return/pure has to carry with it a rest before a stream comes into the picture, though I guess one could argue that (Chunk "") is some kind of identity but this does not seem to be enforced in any way. Furthermore in the bind operator the rest of the iteratee from the bound (RHS) function seems to be ignored at some times and not at others (depending on the rest of the bound LHS value). I am probably missing something obvious or something relating to optimisation/server software but defining iteratees as "Iteratee s a = Cont (s -> Either (s, a) (Iteratee s a))" seems to lead to a more natural monad instance, and does not suffer from (what seems to me to be an issue) having to make predictions about the stream it will be passed. My question is thus, why the "rest" stream has to be carried by an Iteratee constructor, rather then be part of the value of the continuation function.

On Sat, Jun 12, 2010 at 1:12 PM, Tilo Wiklund
I am probably missing something obvious or something relating to optimisation/server software but defining iteratees as "Iteratee s a = Cont (s -> Either (s, a) (Iteratee s a))" seems to lead to a more natural monad instance, and does not suffer from (what seems to me to be an issue) having to make predictions about the stream it will be passed.
If you forget about the monad transformer, your iteratee is essentially the same as the current iteratee in the iteratee package[1]: newtype IterateeG c el m a = IterateeG{ runIter :: StreamG c el -> m (IterGV c el m a) } data IterGV c el m a = Done a (StreamG c el) | Cont (IterateeG c el m a) (Maybe ErrMsg) So a function from a stream to a result which is either done or needs more data. The current iteratee design from Oleg Kiselyov[2] is slightly different however: data Iteratee a = IE_done a Stream | IE_cont (Stream -> Iteratee a) (Maybe ErrMsg) The main advantage of this design is that you can create an iteratee which returns a value without consuming input: return x = IE_done x (Chunk "") instead of: return x = IterateeG (\s -> return $ Done x s) You may also want to read the latest issue of The Monad Reader[3] (issue 16) which contains an article by John W. Lato (author of the iteratee package) which introduces iteratees. [1] http://hackage.haskell.org/packages/archive/iteratee/0.3.5/doc/html/Data-Ite... [2] http://okmij.org/ftp/Haskell/Iteratee/Iteratee.hs [3] http://themonadreader.wordpress.com/2010/05/12/issue-16/
participants (2)
-
Bas van Dijk
-
Tilo Wiklund