[Haskell-cafe] Iteratee IO examples

John Lato jwlato at gmail.com
Sat Jun 25 12:51:48 CEST 2011

From: Eric Rasmussen <ericrasmussen at gmail.com>

> 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.

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/haskell-cafe/attachments/20110625/f9e64c24/attachment.htm>

More information about the Haskell-Cafe mailing list