From: Eric Rasmussen <<a href="mailto:ericrasmussen@gmail.com" target="_blank">ericrasmussen@gmail.com</a>><br><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
Hi,<br>
<br>
Examples are very helpful to me too -- thank you for sharing. I'm especially<br>
curious to see if there are any examples that allow you to use or convert<br>
non-iteratee-based functions. I have only just begun reading about iteratees<br>
and might be missing the point, but it seems like many of the examples so<br>
far rely on explicit recursion or special functions from one of the iteratee<br>
modules.<br></blockquote><div><br>You might be interested in the attoparsec-enumerator and attoparsec-iteratee packages, which adapt attoparsec parsers to work with iteratees. They're small, self-contained, and quite readable. Since attoparsec works with partial parses, it's a natural fit for iteratees.<br>
<br>Honestly I'm quite dis-satisfied with the current state of code which depends on iteratee/enumerator. It's nearly all written in a very low-level style, i.e. directly writing 'liftI step', or 'case x of Yield -> ...'. This is exactly what I would hope users could avoid, by using the functions in e.g. Data.Iteratee.ListLike.<br>
<br>I've recently added more functions to iteratee which greatly reduce the need for this type of code. I don't know about enumerator, but I expect it isn't rich enough since most user code I've seen is pretty low-level.<br>
<br>For some other iteratee examples, you can 'darcs get <a href="http://www.tiresiaspress.us/haskell/sndfile-enumerators/" target="_blank">http://www.tiresiaspress.us/haskell/sndfile-enumerators/</a>' and look at the examples directory (or browse online, of course).<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>
Is there a way to take a simple function (example below) and use an<br>
enumerator to feed it a ByteString from a file, or do you have to write<br>
functions explicitly to work with a given iteratee implementation?<br>
<br>
import qualified Data.ByteString.Char8 as B<br>
sortLines = B.unlines . sort . B.lines<br></blockquote><div><br>For this case, there's no point to using iteratees at all. Just read the file in directly to a strict bytestring. Since you're sorting, you'll need to see all the lines before results can be returned. If the file is too big to fit into memory, you'd need a more sophisticated algorithm for which you could use iteratees.<br>
<br>In the general case, you need to write for a given iteratee implementation, but in many specific cases it's not necessary. If you want to transform each line of a file, for instance (with iteratee):<br><br>import Data.ByteString.Char8 as B<br>
import Data.Iteratee as I<br>import Data.Iteratee.Char<br>import System.IO<br>import Control.Monad.IO.Class<br><br>transform :: (ByteString -> ByteString) -> FilePath -> Iteratee [ByteString] IO ()<br>transform tFunc oFile = do<br>
h <- liftIO $ openFile oFile WriteMode<br> joinI $ rigidMapStream tFunc $ I.mapM_ (B.hPutStrLn h)<br> liftIO $ hClose h<br><br>rewriteFile :: (ByteString -> ByteString) -> FilePath -> FilePath -> IO ()<br>
rewriteFile tFunc iFile oFile = fileDriver (joinI $ enumLinesBS (transform tFunc oFile)) iFile<br><br>An unfolding version would be possible too, which would take a parameter<br><br>tFunc :: (s -> ByteString -> (s, ByteString))<br>
<br>Maybe I'll add these as utilities in the next version of iteratee.<br><br>John<br></div></div>