iteratee 0.8.1.2 → 0.8.2.0
raw patch · 8 files changed
+398/−105 lines, 8 filesdep +mtlPVP ok
version bump matches the API change (PVP)
Dependencies added: mtl
API changes (from Hackage documentation)
+ Data.Iteratee.IO: defaultBufSize :: Int
+ Data.Iteratee.IO: enumFile :: (NullPoint s, MonadCatchIO m, ReadableChunk s el) => Int -> FilePath -> Enumerator s m a
+ Data.Iteratee.IO: enumFileRandom :: (NullPoint s, MonadCatchIO m, ReadableChunk s el) => Int -> FilePath -> Enumerator s m a
+ Data.Iteratee.IO.Handle: enumFile :: (NullPoint s, MonadCatchIO m, ReadableChunk s el) => Int -> FilePath -> Enumerator s m a
+ Data.Iteratee.IO.Handle: enumFileRandom :: (NullPoint s, MonadCatchIO m, ReadableChunk s el) => Int -> FilePath -> Enumerator s m a
+ Data.Iteratee.Iteratee: (<><) :: (Nullable s1, Monad m) => Enumeratee s2 s3 m a -> (forall x. Enumeratee s1 s2 m x) -> Enumeratee s1 s3 m a
+ Data.Iteratee.Iteratee: (><>) :: (Nullable s1, Monad m) => (forall x. Enumeratee s1 s2 m x) -> Enumeratee s2 s3 m a -> Enumeratee s1 s3 m a
+ Data.Iteratee.ListLike: enumWith :: (Monad m, Nullable s, ListLike s el) => Iteratee s m a -> Iteratee s m b -> Iteratee s m (a, b)
+ Data.Iteratee.ListLike: sequence_ :: (Monad m, ListLike s el, Nullable s) => [Iteratee s m a] -> Iteratee s m ()
+ Data.Iteratee.ListLike: zip :: (Monad m, Nullable s, ListLike s el) => Iteratee s m a -> Iteratee s m b -> Iteratee s m (a, b)
+ Data.Iteratee.ListLike: zip3 :: (Monad m, Nullable s, ListLike s el) => Iteratee s m a -> Iteratee s m b -> Iteratee s m c -> Iteratee s m (a, b, c)
+ Data.Iteratee.ListLike: zip4 :: (Monad m, Nullable s, ListLike s el) => Iteratee s m a -> Iteratee s m b -> Iteratee s m c -> Iteratee s m d -> Iteratee s m (a, b, c, d)
+ Data.Iteratee.ListLike: zip5 :: (Monad m, Nullable s, ListLike s el) => Iteratee s m a -> Iteratee s m b -> Iteratee s m c -> Iteratee s m d -> Iteratee s m e -> Iteratee s m (a, b, c, d, e)
Files
- iteratee.cabal +3/−2
- src/Data/Iteratee/IO.hs +5/−0
- src/Data/Iteratee/IO/Fd.hs +3/−4
- src/Data/Iteratee/IO/Handle.hs +26/−9
- src/Data/Iteratee/Iteratee.hs +34/−2
- src/Data/Iteratee/ListLike.hs +219/−66
- tests/foo.hs +0/−11
- tests/testIteratee.hs +108/−11
iteratee.cabal view
@@ -1,5 +1,5 @@ name: iteratee-version: 0.8.1.2+version: 0.8.2.0 synopsis: Iteratee-based I/O description: The Iteratee monad provides strict, safe, and functional I/O. In addition@@ -10,7 +10,7 @@ license: BSD3 license-file: LICENSE homepage: http://www.tiresiaspress.us/haskell/iteratee-tested-with: GHC == 7.0.1, GHC == 6.12.3+tested-with: GHC == 7.0.3, GHC == 6.12.3 stability: experimental cabal-version: >= 1.6@@ -96,6 +96,7 @@ if flag(buildTests) build-depends:+ mtl >= 2 && < 3, QuickCheck >= 2 && < 3, test-framework >= 0.3 && < 0.4, test-framework-quickcheck2 >= 0.2 && < 0.3
src/Data/Iteratee/IO.hs view
@@ -3,10 +3,14 @@ -- |Random and Binary IO with generic Iteratees. module Data.Iteratee.IO(+ -- * Data+ defaultBufSize, -- * File enumerators -- ** Handle-based enumerators enumHandle, enumHandleRandom,+ enumFile,+ enumFileRandom, #if defined(USE_POSIX) -- ** FileDescriptor based enumerators enumFd,@@ -35,6 +39,7 @@ import Control.Monad.CatchIO +-- | The default buffer size. defaultBufSize :: Int defaultBufSize = 1024
src/Data/Iteratee/IO/Fd.hs view
@@ -25,6 +25,7 @@ import Data.Iteratee.Binary() import Data.Iteratee.IO.Base +import Control.Concurrent (yield) import Control.Exception import Control.Monad import Control.Monad.CatchIO as CIO@@ -37,7 +38,6 @@ import System.IO (SeekMode(..)) import System.Posix hiding (FileOffset)-import GHC.Conc -- ------------------------------------------------------------------------ -- Binary Random IO enumerators@@ -50,11 +50,10 @@ -> st -> m (Either SomeException ((Bool, st), s)) makefdCallback p bufsize fd st = do- liftIO $ GHC.Conc.threadWaitRead fd n <- liftIO $ myfdRead fd (castPtr p) bufsize case n of- Left _ -> return $ Left undefined- Right 0 -> return $ Right ((False, st), empty)+ Left _ -> return $ Left (error "myfdRead failed")+ Right 0 -> liftIO yield >> return (Right ((False, st), empty)) Right n' -> liftM (\s -> Right ((True, st), s)) $ readFromPtr p (fromIntegral n')
src/Data/Iteratee/IO/Handle.hs view
@@ -10,6 +10,8 @@ enumHandle ,enumHandleCatch ,enumHandleRandom+ ,enumFile+ ,enumFileRandom -- * Iteratee drivers ,fileDriverHandle ,fileDriverRandomHandle@@ -105,33 +107,48 @@ -- ---------------------------------------------- -- File Driver wrapper functions. -fileDriver :: (NullPoint s, MonadCatchIO m, ReadableChunk s el) =>+enumFile' :: (NullPoint s, MonadCatchIO m, ReadableChunk s el) => (Int -> Handle -> Enumerator s m a) -> Int -- ^Buffer size- -> Iteratee s m a -> FilePath- -> m a-fileDriver enumf bufsize iter filepath = CIO.bracket+ -> Enumerator s m a+enumFile' enumf bufsize filepath iter = CIO.bracket (liftIO $ openBinaryFile filepath ReadMode) (liftIO . hClose)- (run <=< flip (enumf bufsize) iter)+ (flip (enumf bufsize) iter) +enumFile ::+ (NullPoint s, MonadCatchIO m, ReadableChunk s el)+ => Int -- ^Buffer size+ -> FilePath+ -> Enumerator s m a+enumFile = enumFile' enumHandle++enumFileRandom ::+ (NullPoint s, MonadCatchIO m, ReadableChunk s el)+ => Int -- ^Buffer size+ -> FilePath+ -> Enumerator s m a+enumFileRandom = enumFile' enumHandleRandom+ -- |Process a file using the given @Iteratee@. This function wraps -- @enumHandle@ as a convenience. fileDriverHandle :: (NullPoint s, MonadCatchIO m, ReadableChunk s el) =>- Int -- ^Buffer size (number of elements)+ Int -- ^Buffer size (number of elements) -> Iteratee s m a -> FilePath -> m a-fileDriverHandle = fileDriver enumHandle+fileDriverHandle bufsize iter filepath =+ enumFile bufsize filepath iter >>= run -- |A version of @fileDriverHandle@ that supports seeking. fileDriverRandomHandle :: (NullPoint s, MonadCatchIO m, ReadableChunk s el) =>- Int+ Int -- ^ Buffer size (number of elements) -> Iteratee s m a -> FilePath -> m a-fileDriverRandomHandle = fileDriver enumHandleRandom+fileDriverRandomHandle bufsize iter filepath =+ enumFileRandom bufsize filepath iter >>= run
src/Data/Iteratee/Iteratee.hs view
@@ -1,4 +1,8 @@-{-# LANGUAGE KindSignatures, FlexibleContexts, ScopedTypeVariables, DeriveDataTypeable #-}+{-# LANGUAGE KindSignatures+ ,RankNTypes+ ,FlexibleContexts+ ,ScopedTypeVariables+ ,DeriveDataTypeable #-} -- |Monadic and General Iteratees: -- incremental input parsers, processors and transformers@@ -34,6 +38,9 @@ -- ** Enumerator Combinators ,(>>>) ,eneeCheckIfDone+ -- ** Enumeratee Combinators+ ,(><>)+ ,(<><) -- * Misc. ,seek ,FileOffset@@ -133,7 +140,6 @@ step (Chunk xs) | nullC xs = liftI step | True = lift (f xs) >> liftI step- step (Chunk xs) = lift (f xs) >> liftI step step s@(EOF _) = idone () s {-# INLINE mapChunksM_ #-} @@ -256,6 +262,32 @@ (>>>) :: (Monad m) => Enumerator s m a -> Enumerator s m a -> Enumerator s m a (e1 >>> e2) i = e1 i >>= e2+ -- I think (>>>) is identical to (>=>)...+++-- | Enumeratee composition+-- Run the second enumeratee within the first. In this example, stream2list+-- is run within the 'take 10', which is itself run within 'take 15', resulting+-- in 15 elements being consumed+--+-- > run =<< enumPure1Chunk [1..1000 :: Int]+-- > (joinI $ (I.take 15 ><> I.take 10) I.stream2list)+-- > [1,2,3,4,5,6,7,8,9,10]+-- +(><>) ::+ (Nullable s1, Monad m)+ => (forall x . Enumeratee s1 s2 m x)+ -> Enumeratee s2 s3 m a+ -> Enumeratee s1 s3 m a+f ><> g = joinI . f . g++-- | enumeratee composition with the arguments flipped, see '><>'+(<><) ::+ (Nullable s1, Monad m)+ => Enumeratee s2 s3 m a+ -> (forall x. Enumeratee s1 s2 m x)+ -> Enumeratee s1 s3 m a+f <>< g = joinI . g . f -- |The pure 1-chunk enumerator -- It passes a given list of elements to the iteratee in one chunk
src/Data/Iteratee/ListLike.hs view
@@ -45,6 +45,12 @@ ,enumPureNChunk -- ** Enumerator Combinators ,enumPair+ ,enumWith+ ,zip+ ,zip3+ ,zip4+ ,zip5+ ,sequence_ -- ** Monadic functions ,mapM_ ,foldM@@ -53,19 +59,22 @@ ) where -import Prelude hiding (mapM_, null, head, last, drop, dropWhile, take, break, foldl, foldl1, length, filter, sum, product)+import Prelude hiding (mapM_, null, head, last, drop, dropWhile, take, break, foldl, foldl1, length, filter, sum, product, zip, zip3, sequence_) +import qualified Prelude as Prelude+ import qualified Data.ListLike as LL import qualified Data.ListLike.FoldableLL as FLL import Data.Iteratee.Iteratee import Data.Monoid+import Data.Maybe (catMaybes) import Control.Applicative+import Control.Monad (liftM, liftM2, mplus, (<=<)) import Control.Monad.Trans.Class import Data.Word (Word8) import qualified Data.ByteString as B import qualified Data.ByteString.Char8 as BC - -- Useful combinators for implementing iteratees and enumerators -- | Check if a stream has received 'EOF'.@@ -199,8 +208,9 @@ -- | Return a chunk of `t' elements length, while consuming `d' elements -- from the stream. Useful for creating a "rolling average" with convStream.-roll :: (Monad m, Functor m, Nullable s, LL.ListLike s el, LL.ListLike s' s) =>- Int+roll+ :: (Monad m, Functor m, Nullable s, LL.ListLike s el, LL.ListLike s' s)+ => Int -> Int -> Iteratee s m s' roll t d | t > d = liftI step@@ -271,7 +281,10 @@ -- @break@ pred === @joinI@ (@breakE@ pred stream2stream) -- -- @breakE@ should be used in preference to @break@ whenever possible.-breakE :: (Monad m, LL.ListLike s el, NullPoint s) => (el -> Bool) -> Enumeratee s s m a+breakE+ :: (Monad m, LL.ListLike s el, NullPoint s)+ => (el -> Bool)+ -> Enumeratee s s m a breakE cpred = eneeCheckIfDone (liftI . step) where step k (Chunk s)@@ -342,14 +355,14 @@ -- given iteratee to it. -- -- The analog of @List.map@-mapStream ::- (Monad m,- LL.ListLike (s el) el,- LL.ListLike (s el') el',- NullPoint (s el),- LooseMap s el el') =>- (el -> el')- -> Enumeratee (s el) (s el') m a+mapStream+ :: (Monad m+ ,LL.ListLike (s el) el+ ,LL.ListLike (s el') el'+ ,NullPoint (s el)+ ,LooseMap s el el')+ => (el -> el')+ -> Enumeratee (s el) (s el') m a mapStream f = eneeCheckIfDone (liftI . step) where step k (Chunk xs)@@ -363,9 +376,9 @@ -- Like 'mapStream', but the element type cannot change. -- This function is necessary for @ByteString@ and similar types -- that cannot have 'LooseMap' instances, and may be more efficient.-rigidMapStream ::- (Monad m, LL.ListLike s el, NullPoint s) =>- (el -> el)+rigidMapStream+ :: (Monad m, LL.ListLike s el, NullPoint s)+ => (el -> el) -> Enumeratee s s m a rigidMapStream f = eneeCheckIfDone (liftI . step) where@@ -381,9 +394,9 @@ -- satisfy the predicate function. The outer stream is completely consumed. -- -- The analogue of @List.filter@-filter ::- (Monad m, Nullable s, LL.ListLike s el) =>- (el -> Bool)+filter+ :: (Monad m, Nullable s, LL.ListLike s el)+ => (el -> Bool) -> Enumeratee s s m a filter p = convStream f' where@@ -397,8 +410,10 @@ -- |Creates an 'enumeratee' in which elements from the stream are -- grouped into \sz\-sized blocks. The outer stream is completely -- consumed and the final block may be smaller than \sz\.-group :: (LL.ListLike s el, Monad m, Nullable s) => - Int -> Enumeratee s [s] m a+group+ :: (LL.ListLike s el, Monad m, Nullable s)+ => Int+ -> Enumeratee s [s] m a group sz iinit = liftI $ go iinit LL.empty where go icurr pfx (Chunk s) = case gsplit (pfx `LL.append` s) of (full, partial) | LL.null full -> liftI $ go icurr partial@@ -422,8 +437,10 @@ -- -- The analogue of @List.groupBy# -groupBy :: (LL.ListLike s el, Monad m, Nullable s) =>- (el -> el -> Bool) -> Enumeratee s [s] m a+groupBy+ :: (LL.ListLike s el, Monad m, Nullable s)+ => (el -> el -> Bool)+ -> Enumeratee s [s] m a groupBy same iinit = liftI $ go iinit LL.empty where go icurr pfx (Chunk s) = case gsplit (pfx `LL.append` s) of (full, partial)@@ -453,9 +470,9 @@ -- | Left-associative fold. -- -- The analogue of @List.foldl@-foldl ::- (Monad m, LL.ListLike s el, FLL.FoldableLL s el) =>- (a -> el -> a)+foldl+ :: (Monad m, LL.ListLike s el, FLL.FoldableLL s el)+ => (a -> el -> a) -> a -> Iteratee s m a foldl f i = liftI (step i)@@ -471,9 +488,9 @@ -- This function should be used in preference to 'foldl' whenever possible. -- -- The analogue of @List.foldl'@.-foldl' ::- (Monad m, LL.ListLike s el, FLL.FoldableLL s el) =>- (a -> el -> a)+foldl'+ :: (Monad m, LL.ListLike s el, FLL.FoldableLL s el)+ => (a -> el -> a) -> a -> Iteratee s m a foldl' f i = liftI (step i)@@ -488,9 +505,9 @@ -- in the stream. -- -- The analogue of @List.foldl1@.-foldl1 ::- (Monad m, LL.ListLike s el, FLL.FoldableLL s el) =>- (el -> el -> el)+foldl1+ :: (Monad m, LL.ListLike s el, FLL.FoldableLL s el)+ => (el -> el -> el) -> Iteratee s m el foldl1 f = liftI step where@@ -503,9 +520,9 @@ -- | Strict variant of 'foldl1'.-foldl1' ::- (Monad m, LL.ListLike s el, FLL.FoldableLL s el) =>- (el -> el -> el)+foldl1'+ :: (Monad m, LL.ListLike s el, FLL.FoldableLL s el)+ => (el -> el -> el) -> Iteratee s m el foldl1' f = liftI step where@@ -543,42 +560,176 @@ -- Zips -- |Enumerate two iteratees over a single stream simultaneously.+-- Deprecated, use `Data.Iteratee.ListLike.zip` instead. -- -- Compare to @zip@.-enumPair ::- (Monad m, Nullable s, LL.ListLike s el) =>- Iteratee s m a+{-# DEPRECATED enumPair "use Data.Iteratee.ListLike.zip" #-}+enumPair+ :: (Monad m, Nullable s, LL.ListLike s el)+ => Iteratee s m a -> Iteratee s m b- -> Iteratee s m (a,b)-enumPair i1 i2 = Iteratee $ \od oc -> runIter i1 (onDone od oc) (onCont od oc)+ -> Iteratee s m (a, b)+enumPair = zip+++-- |Enumerate two iteratees over a single stream simultaneously.+--+-- Compare to @zip@.+zip+ :: (Monad m, Nullable s, LL.ListLike s el)+ => Iteratee s m a+ -> Iteratee s m b+ -> Iteratee s m (a, b)+zip x y = liftI step where- onDone od oc x s = runIter i2 (oD12 od oc x s) (onCont' od oc x)- oD12 od oc x1 s1 x2 s2 = runIter (idone (x1,x2) (longest s1 s2)) od oc- onCont od oc k mErr = runIter (icont (step k) mErr) od oc+ step (Chunk xs) | nullC xs = liftI step+ step (Chunk xs) = do+ (a', x') <- lift $ (\i -> runIter i od oc) =<< enumPure1Chunk xs x+ (b', y') <- lift $ (\i -> runIter i od oc) =<< enumPure1Chunk xs y+ case checkDone a' b' of+ Just (a, b, s) -> idone (a, b) s+ Nothing -> zip x' y'+ step (EOF err) = joinIM $ case err of+ Nothing -> (liftM2.liftM2) (,) (enumEof x) (enumEof y)+ Just e -> (liftM2.liftM2) (,) (enumErr e x) (enumErr e y)++ od a s = return (Just (a, s), idone a s)+ oc k e = return (Nothing , icont k e)++ checkDone r1 r2 =+ r1 >>= \(a, s1) -> r2 >>= \(b, s2) ->+ return (a, b, shorter s1 s2)++ shorter c1@(Chunk xs) c2@(Chunk ys)+ | LL.length xs < LL.length ys = c1+ | otherwise = c2+ shorter e@(EOF _) _ = e+ shorter _ e@(EOF _) = e+{-# INLINE zip #-}++zip3+ :: (Monad m, Nullable s, LL.ListLike s el)+ => Iteratee s m a -> Iteratee s m b+ -> Iteratee s m c -> Iteratee s m (a, b, c)+zip3 a b c = zip a (zip b c) >>=+ \(r1, (r2, r3)) -> return (r1, r2, r3)+{-# INLINE zip3 #-}++zip4+ :: (Monad m, Nullable s, LL.ListLike s el)+ => Iteratee s m a -> Iteratee s m b+ -> Iteratee s m c -> Iteratee s m d+ -> Iteratee s m (a, b, c, d)+zip4 a b c d = zip a (zip3 b c d) >>=+ \(r1, (r2, r3, r4)) -> return (r1, r2, r3, r4)+{-# INLINE zip4 #-}++zip5+ :: (Monad m, Nullable s, LL.ListLike s el)+ => Iteratee s m a -> Iteratee s m b+ -> Iteratee s m c -> Iteratee s m d+ -> Iteratee s m e -> Iteratee s m (a, b, c, d, e)+zip5 a b c d e = zip a (zip4 b c d e) >>=+ \(r1, (r2, r3, r4, r5)) -> return (r1, r2, r3, r4, r5)+{-# INLINE zip5 #-}++-- | Enumerate over two iteratees in parallel as long as the first iteratee+-- is still consuming input. The second iteratee will be terminated with EOF+-- when the first iteratee has completed. An example use is to determine+-- how many elements an iteratee has consumed:+--+-- > snd <$> enumWith (dropWhile (<5)) length+--+-- Compare to @zip@+enumWith+ :: (Monad m, Nullable s, LL.ListLike s el)+ => Iteratee s m a+ -> Iteratee s m b+ -> Iteratee s m (a, b)+enumWith i1 i2 = go i1 i2+ where+ od a s = return (Just (a, s), idone a s)+ oc k e = return (Nothing , icont k e)++ getUsed xs (Chunk ys) = LL.take (LL.length xs - LL.length ys) xs+ getUsed xs (EOF _) = xs++ go x y = liftI step where- onCont' od oc x1 k mErr = runIter (icont (step2 x1 k) mErr) od oc- step k c@(Chunk str)- | nullC str = liftI (step k)- | True = lift (enumPure1Chunk str i2) >>= enumPair (k c)- step k s@(EOF Nothing) = lift (enumEof i2) >>= enumPair (k s)- step k s@(EOF (Just e)) = lift (enumErr e i2) >>= enumPair (k s)- step2 x1 k (Chunk str)- | nullC str = liftI (step2 x1 k)- step2 x1 k str = enumPair (return x1) (k str)- longest c1@(Chunk xs) c2@(Chunk ys) = if LL.length xs > LL.length ys- then c1 else c2- longest e@(EOF _) _ = e- longest _ e@(EOF _) = e-{-# INLINE enumPair #-}+ step (Chunk xs) | nullC xs = liftI step+ step (Chunk xs) = do+ (a', x') <- lift $ (\i -> runIter i od oc) =<< enumPure1Chunk xs x+ case a' of+ Just (a, s) -> do+ b <- lift $ run =<< enumPure1Chunk (getUsed xs s) y+ idone (a, b) s+ Nothing -> lift (enumPure1Chunk xs y) >>= go x'+ step (EOF err) = joinIM $ case err of+ Nothing -> (liftM2.liftM2) (,) (enumEof x) (enumEof y)+ Just e -> (liftM2.liftM2) (,) (enumErr e x) (enumErr e y)+{-# INLINE enumWith #-} +-- |Enumerate a list of iteratees over a single stream simultaneously+-- and discard the results. This is a different behavior than Prelude's+-- sequence_ which runs iteratees in the list one after the other.+--+-- Compare to @sequence_@.+sequence_+ :: (Monad m, LL.ListLike s el, Nullable s)+ => [Iteratee s m a]+ -> Iteratee s m ()+sequence_ = self+ where+ self is = liftI step+ where+ step (Chunk xs) | LL.null xs = liftI step+ step s@(Chunk _) = do+ -- give a chunk to each iteratee+ is' <- lift $ mapM (enumChunk s) is+ -- filter done iteratees+ is'' <- lift $ catMaybes `liftM` mapM checkIfDone is'+ if Prelude.null is''+ then idone () <=< remainingStream $ is'+ else self is''+ step s@(EOF _) = do+ s' <- remainingStream <=< lift $ mapM (enumChunk s) $ is+ case s' of+ EOF (Just e) -> throwErr e+ _ -> idone () s' + checkIfDone i = runIter i+ (\_ _ -> return Nothing)+ (\k e -> return $ Just $ icont k e)++ -- returns the unconsumed part of the stream; "sequence_ is" consumes as+ -- much of the stream as the iteratee in is that consumes the most; e.g.+ -- sequence_ [I.head, I.last] consumes whole stream+ remainingStream+ :: (Monad m, Nullable s, LL.ListLike s el)+ => [Iteratee s m a] -> Iteratee s m (Stream s)+ remainingStream is = lift $+ return . Prelude.foldl1 shorter <=< mapM (\i -> runIter i od oc) $ is+ where+ od _ s = return s+ oc _ e = return $ case e of+ Nothing -> mempty+ _ -> EOF e++ -- return the shorter one of two streams; errors are propagated with the+ -- priority given to the "left"+ shorter c1@(Chunk xs) c2@(Chunk ys)+ | LL.length xs < LL.length ys = c1+ | otherwise = c2+ shorter (EOF e1 ) (EOF e2 ) = EOF (e1 `mplus` e2)+ shorter e@(EOF _) _ = e+ shorter _ e@(EOF _) = e+ -- ------------------------------------------------------------------------ -- Enumerators -- |The pure n-chunk enumerator -- It passes a given stream of elements to the iteratee in @n@-sized chunks.-enumPureNChunk ::- (Monad m, LL.ListLike s el) => s -> Int -> Enumerator s m a+enumPureNChunk :: (Monad m, LL.ListLike s el) => s -> Int -> Enumerator s m a enumPureNChunk str n iter | LL.null str = return iter | n > 0 = enum' str iter@@ -598,9 +749,10 @@ -- | Map a monadic function over the elements of the stream and ignore the -- result.-mapM_ :: (Monad m, LL.ListLike s el, Nullable s)- => (el -> m b)- -> Iteratee s m ()+mapM_+ :: (Monad m, LL.ListLike s el, Nullable s)+ => (el -> m b)+ -> Iteratee s m () mapM_ f = liftI step where step (Chunk xs) | LL.null xs = liftI step@@ -609,10 +761,11 @@ {-# INLINE mapM_ #-} -- |The analogue of @Control.Monad.foldM@-foldM :: (Monad m, LL.ListLike s b, Nullable s)- => (a -> b -> m a)- -> a- -> Iteratee s m a+foldM+ :: (Monad m, LL.ListLike s b, Nullable s)+ => (a -> b -> m a)+ -> a+ -> Iteratee s m a foldM f e = liftI step where step (Chunk xs) | LL.null xs = liftI step
− tests/foo.hs
@@ -1,11 +0,0 @@-import Control.Monad.Trans (liftIO)-import Data.Iteratee.Iteratee-import qualified Data.Iteratee.ListLike as I--main = enumPure1Chunk [1..10] myIter >>= run--myIter :: Iteratee [Int] IO ()-myIter = do- I.last- x <- I.peek- liftIO $ print x
tests/testIteratee.hs view
@@ -10,14 +10,17 @@ import Test.QuickCheck -import Data.Iteratee hiding (head, break)+import Data.Iteratee hiding (head, break) import qualified Data.Iteratee.Char as IC import qualified Data.Iteratee as Iter-import Data.Functor.Identity+import Data.Functor.Identity import qualified Data.List as List (groupBy, unfoldr)-import Data.Monoid+import Data.Monoid import qualified Data.ListLike as LL +import Control.Monad as CM+import Control.Monad.Writer+ import Text.Printf (printf) import System.Environment (getArgs) @@ -53,8 +56,8 @@ -- --------------------------------------------- -- Iteratee instances -runner0 = runIdentity . Iter.run runner1 = runIdentity . Iter.run . runIdentity+enumSpecial xs n = enumPure1Chunk LL.empty >=> enumPureNChunk xs n prop_iterFmap xs f a = runner1 (enumPure1Chunk xs (fmap f $ return a)) == runner1 (enumPure1Chunk xs (return $ f a))@@ -64,15 +67,15 @@ == f (runner1 (enumPure1Chunk xs i)) where types = (xs :: [Int], i :: I, f :: [Int] -> [Int]) -prop_iterMonad1 xs a f = runner1 (enumPureNChunk xs 1 (return a >>= f))+prop_iterMonad1 xs a f = runner1 (enumSpecial xs 1 (return a >>= f)) == runner1 (enumPure1Chunk xs (f a)) where types = (xs :: [Int], a :: Int, f :: Int -> I) -prop_iterMonad2 m xs = runner1 (enumPureNChunk xs 1 (m >>= return))+prop_iterMonad2 m xs = runner1 (enumSpecial xs 1 (m >>= return)) == runner1 (enumPure1Chunk xs m) where types = (xs :: [Int], m :: I) -prop_iterMonad3 m f g xs = runner1 (enumPureNChunk xs 1 ((m >>= f) >>= g))+prop_iterMonad3 m f g xs = runner1 (enumSpecial xs 1 ((m >>= f) >>= g)) == runner1 (enumPure1Chunk xs (m >>= (\x -> f x >>= g))) where types = (xs :: [Int], m :: I, f :: [Int] -> I, g :: [Int] -> I) @@ -82,7 +85,7 @@ prop_list xs = runner1 (enumPure1Chunk xs stream2list) == xs where types = xs :: [Int] -prop_clist xs n = n > 0 ==> runner1 (enumPureNChunk xs n stream2list) == xs+prop_clist xs n = n > 0 ==> runner1 (enumSpecial xs n stream2list) == xs where types = xs :: [Int] prop_break f xs = runner1 (enumPure1Chunk xs (Iter.break f)) == fst (break f xs)@@ -104,7 +107,8 @@ prop_head2 xs = P.length xs > 0 ==> runner1 (enumPure1Chunk xs (Iter.head >> stream2list)) == tail xs where types = xs :: [Int] -prop_heads xs = runner1 (enumPure1Chunk xs $ heads xs) == P.length xs+prop_heads xs n = n > 0 ==>+ runner1 (enumSpecial xs n $ heads xs) == P.length xs where types = xs :: [Int] prop_heads2 xs = runner1 (enumPure1Chunk xs $ heads [] >>= \c ->@@ -132,13 +136,25 @@ runner1 (enumPure1Chunk xs (Iter.last >> Iter.peek)) == Nothing where types = xs :: [Int] +prop_drop xs n k = (n > 0 && k >= 0) ==>+ runner1 (enumSpecial xs n (Iter.drop k >> stream2list)) == P.drop k xs+ where types = xs :: [Int]++prop_dropWhile f xs =+ runner1 (enumPure1Chunk xs (Iter.dropWhile f >> stream2list))+ == P.dropWhile f xs+ where types = (xs :: [Int], f :: Int -> Bool)++prop_length xs = runner1 (enumPure1Chunk xs Iter.length) == P.length xs+ where types = xs :: [Int]+ -- --------------------------------------------- -- Simple enumerator tests type I = Iteratee [Int] Identity [Int] prop_enumChunks n xs i = n > 0 ==>- runner1 (enumPure1Chunk xs i) == runner1 (enumPureNChunk xs n i)+ runner1 (enumPure1Chunk xs i) == runner1 (enumSpecial xs n i) where types = (n :: Int, xs :: [Int], i :: I) prop_app1 xs ys i = runner1 (enumPure1Chunk ys (joinIM $ enumPure1Chunk xs i))@@ -170,7 +186,20 @@ runner1 (enumPure1Chunk xs =<< enumPure1Chunk [] Iter.head) == runner1 (enumPure1Chunk xs Iter.head) where types = xs :: [Int]+ -- ---------------------------------------------+-- Enumerator Combinators++prop_enumWith xs f n = n > 0 ==> runner1 (enumSpecial xs n $ fmap fst $ enumWith (Iter.dropWhile f) (stream2list))+ == runner1 (enumSpecial xs n $ Iter.dropWhile f)+ where types = (xs :: [Int])++prop_enumWith2 xs f n = n > 0 ==> runner1 (enumSpecial xs n $ enumWith (Iter.dropWhile f) (stream2list) >> stream2list)+ == runner1 (enumSpecial xs n $ Iter.dropWhile f >> stream2list)+ where types = (xs :: [Int])+++-- --------------------------------------------- -- Nested Iteratees -- take, mapStream, convStream, and takeR@@ -182,7 +211,7 @@ where types = (i :: I, xs :: [Int]) prop_mapStream2 xs n i = n > 0 ==>- runner2 (enumPureNChunk xs n $ mapStream id i)+ runner2 (enumSpecial xs n $ mapStream id i) == runner1 (enumPure1Chunk xs i) where types = (i :: I, xs :: [Int]) @@ -191,7 +220,33 @@ == runner1 (enumPure1Chunk xs i) where types = (i :: I, xs :: [Int]) +prop_rigidMapStream xs n f = n > 0 ==>+ runner2 (enumSpecial xs n $ rigidMapStream f stream2list) == map f xs+ where types = (xs :: [Int]) +prop_foldl xs n f x0 = n > 0 ==>+ runner1 (enumSpecial xs n (Iter.foldl f x0)) == P.foldl f x0 xs+ where types = (xs :: [Int], x0 :: Int)++prop_foldl' xs n f x0 = n > 0 ==>+ runner1 (enumSpecial xs n (Iter.foldl' f x0)) == LL.foldl' f x0 xs+ where types = (xs :: [Int], x0 :: Int)++prop_foldl1 xs n f = (n > 0 && not (null xs)) ==>+ runner1 (enumSpecial xs n (Iter.foldl1 f)) == P.foldl1 f xs+ where types = (xs :: [Int])++prop_foldl1' xs n f = (n > 0 && not (null xs)) ==>+ runner1 (enumSpecial xs n (Iter.foldl1' f)) == P.foldl1 f xs+ where types = (xs :: [Int])++prop_sum xs n = n > 0 ==> runner1 (enumSpecial xs n Iter.sum) == P.sum xs+ where types = (xs :: [Int])++prop_product xs n = n > 0 ==>+ runner1 (enumSpecial xs n Iter.product) == P.product xs+ where types = (xs :: [Int])+ convId :: (LL.ListLike s el, Monad m) => Iteratee s m s convId = liftI (\str -> case str of s@(Chunk xs) | LL.null xs -> convId@@ -232,6 +287,14 @@ == runner2 (enumPure1Chunk xs $ takeUpTo n stream2list) where types = xs :: [Int] +prop_takeUpTo2 xs n = n >= 0 ==>+ runner2 (enumPure1Chunk xs (takeUpTo n identity)) == ()+ where types = xs :: [Int]++prop_filter xs n f = n > 0 ==>+ runner2 (enumSpecial xs n (Iter.filter f stream2list)) == P.filter f xs+ where types = xs :: [Int]+ prop_group xs n = n > 0 ==> runner2 (enumPure1Chunk xs $ Iter.group n stream2list) == runner1 (enumPure1Chunk groups stream2list)@@ -247,6 +310,18 @@ where types = xs :: [Int] pred z1 z2 = (z1 `mod` m == z2 `mod` m) +prop_mapM_ xs n = n > 0 ==>+ runWriter ((enumSpecial xs n (Iter.mapM_ f)) >>= run)+ == runWriter (CM.mapM_ f xs)+ where f = const $ tell (Sum 1)+ types = xs :: [Int]++prop_foldM xs x0 n = n > 0 ==>+ runWriter ((enumSpecial xs n (Iter.foldM f x0)) >>= run)+ == runWriter (CM.foldM f x0 xs)+ where f acc el = tell (Sum 1) >> return (acc - el)+ types = xs :: [Int]+ -- --------------------------------------------- -- Data.Iteratee.Char @@ -284,6 +359,9 @@ ,testProperty "peek2" prop_peek2 ,testProperty "last" prop_last1 ,testProperty "last ends properly" prop_last2+ ,testProperty "length" prop_length+ ,testProperty "drop" prop_drop+ ,testProperty "dropWhile" prop_dropWhile ,testProperty "skipToEof" prop_skip ,testProperty "iteratee Functor 1" prop_iterFmap ,testProperty "iteratee Functor 2" prop_iterFmap2@@ -306,20 +384,39 @@ testProperty "mapStream identity" prop_mapStream ,testProperty "mapStream identity 2" prop_mapStream2 ,testProperty "mapStream identity joinI" prop_mapjoin+ ,testProperty "rigidMapStream" prop_rigidMapStream ,testProperty "breakE" prop_breakE ,testProperty "breakE remainder" prop_breakE2 ,testProperty "take" prop_take ,testProperty "take (finished iteratee)" prop_take2 ,testProperty "takeUpTo" prop_takeUpTo+ ,testProperty "takeUpTo (finished iteratee)" prop_takeUpTo2+ ,testProperty "filter" prop_filter ,testProperty "group" prop_group ,testProperty "groupBy" prop_groupBy ,testProperty "convStream EOF" prop_convstream2 ,testProperty "convStream identity" prop_convstream ,testProperty "convStream identity 2" prop_convstream3 ]+ ,testGroup "Enumerator Combinators" [+ testProperty "enumWith" prop_enumWith+ ,testProperty "enumWith remaining" prop_enumWith2+ ]+ ,testGroup "Folds" [+ testProperty "foldl" prop_foldl+ ,testProperty "foldl'" prop_foldl'+ ,testProperty "foldl1" prop_foldl1+ ,testProperty "foldl1'" prop_foldl1'+ ,testProperty "sum" prop_sum+ ,testProperty "product" prop_product+ ] ,testGroup "Data.Iteratee.Char" [ --testProperty "line" prop_line ]+ ,testGroup "Monadic functions" [+ testProperty "mapM_" prop_mapM_+ ,testProperty "foldM" prop_foldM+ ] ] ------------------------------------------------------------------------