[Haskell-cafe] 'Progress bar' enumeratee
David Hotham
david.hotham at blueyonder.co.uk
Thu Apr 7 20:17:46 CEST 2011
Very interesting - thanks!
"Gregory Collins" <greg at gregorycollins.net> wrote in message
news:BANLkTikEh7aQfe2-JDq6DoCZ+SYw5MJ5Lg at mail.gmail.com...
> 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 <greg at gregorycollins.net>
More information about the Haskell-Cafe
mailing list