Enumerators, Enumeratees and Iterators

Hey Café. I've been playing with Enumerators, Iteratees and Enumeratees today after having spent a few days writing a server application using lazy IO, then reading slides from Oleg's DEFUN8 talk notes, and I quote: "Lazy IO in serious, server-side programming is unprofessional", "I can talk a lot how disturbingly, distressingly wrong lazy IO is theoretically, how it breaks all equational reasoning" after which my OCD self has been eating me up to take a proper look at this, so here I am. I'm already beginning to see how Iteratees, Enumerators and Enumeratees can be nifty, but I have a couple of questions about a couple of ideas and whether, and if so how they can be implemented. The first question is, I think, to be solved with enumeratees but I can't really grok how. Let's say I have an iteratee that consumes all input. Is it possible to implement an enumeratee or something else to stick between the enumerator and the iteratee to basically modify the input to the iteratee to only be a part of the input? Something like this: enumFile "someFile" && printFileLines -- prints file with prepended line numbers enumFile "someFile" ?? onlyGet10Lines && printFileLines -- print only 10 lines The second question could actually have an application in the server I'm writing. I was wondering if it was possible to write iteratees/enumerators that would only generate/consume when a certain something was the next chunk to be processed? It's a bit hard to explain, but let me try to give you an example. Let's say my application takes input from the network which contains commands that the server reacts to. Let's say I have a list of command handlers that I want to run this command through, but the handlers will only execute when they are passed the command that they are responsible for handling. Can this list of command handlers be enumerators/iteratees/enumeratees? E.g. is it possible to 'concat' them, making them each peek at the next chunk to see if it's theirs to handle and put it back if it isn't? I know this is possible to do differently and I have an idea for how I would do this, but I'm wondering if this is possible. If I can get answers to either or both of the questions it would help me a bit on my way to completely realize the roles that enumerators vs. iteratees vs. enumeratees have, as the lines seem a bit blurred -- sometimes, anyway. Thanks in advance. :)

Hi,
for the first question you can look at combinators in
Data.Iteratee.ListLikehttp://hackage.haskell.org/packages/archive/iteratee/0.8.5.0/doc/html/Data-I...
for iteratee package or
Data.Enumerator.Listhttp://hackage.haskell.org/packages/archive/enumerator/0.4.10/doc/html/Data-...
for
enumerator package.
I doubt that I understand the second question. It seems that Map is more
natural here. You can transform list into enumerator for instance by
enumListhttp://hackage.haskell.org/packages/archive/enumerator/0.4.10/doc/html/Data-....
But I wonder what is the reason for that in your case?
2011/6/28 Sævar Berg
Hey Café.
I've been playing with Enumerators, Iteratees and Enumeratees today after having spent a few days writing a server application using lazy IO, then reading slides from Oleg's DEFUN8 talk notes, and I quote: "Lazy IO in serious, server-side programming is unprofessional", "I can talk a lot how disturbingly, distressingly wrong lazy IO is theoretically, how it breaks all equational reasoning" after which my OCD self has been eating me up to take a proper look at this, so here I am.
I'm already beginning to see how Iteratees, Enumerators and Enumeratees can be nifty, but I have a couple of questions about a couple of ideas and whether, and if so how they can be implemented.
The first question is, I think, to be solved with enumeratees but I can't really grok how. Let's say I have an iteratee that consumes all input. Is it possible to implement an enumeratee or something else to stick between the enumerator and the iteratee to basically modify the input to the iteratee to only be a part of the input?
Something like this:
enumFile "someFile" && printFileLines -- prints file with prepended line numbers enumFile "someFile" ?? onlyGet10Lines && printFileLines -- print only 10 lines
The second question could actually have an application in the server I'm writing. I was wondering if it was possible to write iteratees/enumerators that would only generate/consume when a certain something was the next chunk to be processed? It's a bit hard to explain, but let me try to give you an example.
Let's say my application takes input from the network which contains commands that the server reacts to. Let's say I have a list of command handlers that I want to run this command through, but the handlers will only execute when they are passed the command that they are responsible for handling. Can this list of command handlers be enumerators/iteratees/enumeratees? E.g. is it possible to 'concat' them, making them each peek at the next chunk to see if it's theirs to handle and put it back if it isn't?
I know this is possible to do differently and I have an idea for how I would do this, but I'm wondering if this is possible. If I can get answers to either or both of the questions it would help me a bit on my way to completely realize the roles that enumerators vs. iteratees vs. enumeratees have, as the lines seem a bit blurred -- sometimes, anyway.
Thanks in advance. :)
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

Sævar Berg
The first question is, I think, to be solved with enumeratees but I can't really grok how. Let's say I have an iteratee that consumes all input. Is it possible to implement an enumeratee or something else to stick between the enumerator and the iteratee to basically modify the input to the iteratee to only be a part of the input?
Yes, this is an enumeratee. An enumeratee is neither a data producder nor a consumer. It is an iteratee, which feeds another iteratee with input based on its own input, so it acts like a kind of map operation.
enumFile "someFile" && printFileLines -- prints file with prepended line numbers enumFile "someFile" ?? onlyGet10Lines && printFileLines -- print only 10 lines
In fact an enumeratee can split the input stream into lines. Another one can zip the stream with a list. A final one can take 10 lines from the stream. The code would look like this (in the 'enumerator' package): enumFile "myFile.txt" $$ lines =$ zipWithList [1..] =$ take 10 =$ printLines where lines :: Monad m => Enumeratee Text Text m b zipWithList :: Monad m => [a'] -> Enumeratee a (a, a') m b take :: Monad m => Int -> Enumeratee a a m b printLines :: MonadIO m => Iteratee (Int, Text) m () This is how I would do it.
The second question could actually have an application in the server I'm writing. I was wondering if it was possible to write iteratees/enumerators that would only generate/consume when a certain something was the next chunk to be processed?
You want concurrent iteratees here. As far as I know in the 'enumerator' package there is no builtin way to do it (you may be luckier in the 'iteratee' package, but I don't know). However, I think it should be possible to write a 'concurrent' function, if the iteratees in question all have the same input type: concurrent :: Monad m => [Step a m b] -> Iteratee a m [b] A version, which doesn't collect the results is probably much easier to write: concurrent_ :: Monad m => [Step a m b] -> Iteratee a m () Greets, Ertugrul -- nightmare = unsafePerformIO (getWrongWife >>= sex) http://ertes.de/

If I've understood it correctly, "concurrent" is similar to functions
discussed here:
http://www.haskell.org/pipermail/haskell-cafe/2011-April/091474.html
and here
http://www.haskell.org/pipermail/haskell-cafe/2011-January/088319.html
2011/6/28 Ertugrul Soeylemez
Sævar Berg
wrote: The first question is, I think, to be solved with enumeratees but I can't really grok how. Let's say I have an iteratee that consumes all input. Is it possible to implement an enumeratee or something else to stick between the enumerator and the iteratee to basically modify the input to the iteratee to only be a part of the input?
Yes, this is an enumeratee. An enumeratee is neither a data producder nor a consumer. It is an iteratee, which feeds another iteratee with input based on its own input, so it acts like a kind of map operation.
enumFile "someFile" && printFileLines -- prints file with prepended line numbers enumFile "someFile" ?? onlyGet10Lines && printFileLines -- print only 10 lines
In fact an enumeratee can split the input stream into lines. Another one can zip the stream with a list. A final one can take 10 lines from the stream. The code would look like this (in the 'enumerator' package):
enumFile "myFile.txt" $$ lines =$ zipWithList [1..] =$ take 10 =$ printLines
where
lines :: Monad m => Enumeratee Text Text m b zipWithList :: Monad m => [a'] -> Enumeratee a (a, a') m b take :: Monad m => Int -> Enumeratee a a m b printLines :: MonadIO m => Iteratee (Int, Text) m ()
This is how I would do it.
The second question could actually have an application in the server I'm writing. I was wondering if it was possible to write iteratees/enumerators that would only generate/consume when a certain something was the next chunk to be processed?
You want concurrent iteratees here. As far as I know in the 'enumerator' package there is no builtin way to do it (you may be luckier in the 'iteratee' package, but I don't know). However, I think it should be possible to write a 'concurrent' function, if the iteratees in question all have the same input type:
concurrent :: Monad m => [Step a m b] -> Iteratee a m [b]
A version, which doesn't collect the results is probably much easier to write:
concurrent_ :: Monad m => [Step a m b] -> Iteratee a m ()
Greets, Ertugrul
-- nightmare = unsafePerformIO (getWrongWife >>= sex) http://ertes.de/
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On Mon, Jun 27, 2011 at 7:21 PM, Sævar Berg
The first question is, I think, to be solved with enumeratees but I can't really grok how. Let's say I have an iteratee that consumes all input. Is it possible to implement an enumeratee or something else to stick between the enumerator and the iteratee to basically modify the input to the iteratee to only be a part of the input?
Yes. You would want to use an enumeratee. Consider the following (based on the Enumerator package). It checks each element of the stream against a Set. If the element is in the set, then we do not forward the element to the inner iteratee. If the element is not in the set, we insert it and forward it to the inner iteratee. We "need" loop to carry the Set's state around. unique :: forall a m b . (Ord a, Monad m) => Enumeratee a a m b unique = loop Set.empty where loop :: (Ord a, Monad m) => Set a -> Enumeratee a a m b loop seen step@(Continue k) = continue go where go :: (Ord a, Monad m) => Stream a -> Iteratee a m (Step a m b) go EOF = return step go (Chunks (a:as)) = do (if (a `member` seen) then k $ Chunks as -- drop a if already seen else k $ Chunks (a:as)) -- keep a if not seen >>== loop (a `Set.insert` seen) go ch = (k ch >>== loop seen) loop seen step = return step
Something like this:
enumFile "someFile" && printFileLines -- prints file with prepended line numbers enumFile "someFile" ?? onlyGet10Lines && printFileLines -- print only 10 lines
The second question could actually have an application in the server I'm writing. I was wondering if it was possible to write iteratees/enumerators that would only generate/consume when a certain something was the next chunk to be processed? It's a bit hard to explain, but let me try to give you an example.
Perhaps, but it might be tricky depending on how much you /need/ the certain something to be a Chunk. Look at the 'unique' example above. Notice how we're pattern matching against a Chunk and its inner list. This would be the basis for your conditional matching. I would suggest that you don't want your "certain something" to be a chunk, but an element of the stream (i.e, one of the xs contained in Chunk xs)
participants (4)
-
Alexander Solla
-
Dmitry Olshansky
-
Ertugrul Soeylemez
-
Sævar Berg