
From: Eric Rasmussen
Hi,
Examples are very helpful to me too -- thank you for sharing. I'm especially curious to see if there are any examples that allow you to use or convert non-iteratee-based functions. I have only just begun reading about iteratees and might be missing the point, but it seems like many of the examples so far rely on explicit recursion or special functions from one of the iteratee modules.
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. 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. 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. For some other iteratee examples, you can 'darcs get http://www.tiresiaspress.us/haskell/sndfile-enumerators/' and look at the examples directory (or browse online, of course).
Is there a way to take a simple function (example below) and use an enumerator to feed it a ByteString from a file, or do you have to write functions explicitly to work with a given iteratee implementation?
import qualified Data.ByteString.Char8 as B sortLines = B.unlines . sort . B.lines
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. 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): import Data.ByteString.Char8 as B import Data.Iteratee as I import Data.Iteratee.Char import System.IO import Control.Monad.IO.Class transform :: (ByteString -> ByteString) -> FilePath -> Iteratee [ByteString] IO () transform tFunc oFile = do h <- liftIO $ openFile oFile WriteMode joinI $ rigidMapStream tFunc $ I.mapM_ (B.hPutStrLn h) liftIO $ hClose h rewriteFile :: (ByteString -> ByteString) -> FilePath -> FilePath -> IO () rewriteFile tFunc iFile oFile = fileDriver (joinI $ enumLinesBS (transform tFunc oFile)) iFile An unfolding version would be possible too, which would take a parameter tFunc :: (s -> ByteString -> (s, ByteString)) Maybe I'll add these as utilities in the next version of iteratee. John