Very interesting - thanks!

"Gregory Collins" <[email protected]> wrote in message news:[email protected]...
My enumerator style may not be the best (I'm long-winded), but
personally when the stream types are the same on input and output I
often skip the Enumeratee stuff and just write an Enumerator wrapper.
To address your complaint here:

PS Implementations which involve "EB.take count" seem to me unsatisfactory;
one surely oughtn't need to have a large buffer to solve this problem

I'd write a helping combinator:

module Main where

import           Control.Monad              (when)
import           Control.Monad.Trans
import           Data.ByteString.Char8      (ByteString)
import qualified Data.ByteString.Lazy.Char8 as L
import           Data.Enumerator
import qualified Data.Enumerator.List       as EL
import           System.IO

takeUpTo :: Monad m =>
            Int
         -> Iteratee ByteString m (Stream ByteString, Int)
takeUpTo n' = continue k
  where
    n = toEnum n'

    k EOF         = yield (EOF,0) EOF
    k (Chunks xs) = if taken == 0
                      then takeUpTo n'
                      else yield (stream, taken) rest
      where
        s      = L.fromChunks xs
        (a,b)  = L.splitAt n s
        taken  = fromEnum $ L.length a
        stream = Chunks $ L.toChunks a
        rest   = Chunks $ L.toChunks b


The code to run a side effect every N bytes is then pretty short (and
should be efficient):

sideEffectEveryNBytes :: Monad m =>
                         Int      -- ^ run the side effect every N bytes
                      -> m ()     -- ^ side effect
                      -> Step ByteString m a
                      -> Iteratee ByteString m a
sideEffectEveryNBytes n act = flip checkContinue1 n $ \loop i k -> do
        (str, taken) <- takeUpTo i
        when (taken == i) $ lift act
        (lift $ runIteratee $ k str) >>= loop (nextI $ i - taken)
  where
    nextI 0 = n
    nextI i = i

Here's your particular example:

example :: IO [ByteString]
example = run_ $ enumList 1 [ "the quick brown "
                            , "fox "
                            , "jumped "
                            , "over "
                            , "the lazy dog" ] $$ it
  where
    it = do
        xs <- sideEffectEveryNBytes 10 (putStr "." >> hFlush stdout) $$
              EL.consume
        lift $ putStrLn ""
        return xs

Running it:

*Main> example
....
["the quick ","brown ","fox ","jumped ","ove","r ","the lazy"," dog"]

G
--
Gregory Collins <[email protected]>



_______________________________________________
Haskell-Cafe mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/haskell-cafe

Reply via email to