[Haskell-cafe] 'Progress bar' enumeratee
greg at gregorycollins.net
Wed Apr 6 21:39:20 CEST 2011
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 =>
> -> Iteratee ByteString m (Stream ByteString, Int)
> takeUpTo n' = continue k
> n = toEnum n'
> k EOF = yield (EOF,0) EOF
> k (Chunks xs) = if taken == 0
> then takeUpTo n'
> else yield (stream, taken) rest
> 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)
> 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
> it = do
> xs <- sideEffectEveryNBytes 10 (putStr "." >> hFlush stdout) $$
> lift $ putStrLn ""
> return xs
> *Main> example
> ["the quick ","brown ","fox ","jumped ","ove","r ","the lazy"," dog"]
Gregory Collins <greg at gregorycollins.net>
More information about the Haskell-Cafe