packages feed

enumerator 0.1 → 0.1.1

raw patch · 9 files changed

+184/−28 lines, 9 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Data.Enumerator: ($$) :: (Monad m) => (Step e a m b -> Iteratee e a' m b') -> Iteratee e a m b -> Iteratee e a' m b'
+ Data.Enumerator: (<==<) :: (Monad m) => (Step e a m b -> Iteratee e a' m b') -> Enumerator e a m b -> Step e a m b -> Iteratee e a' m b'
+ Data.Enumerator: (>==>) :: (Monad m) => Enumerator e a m b -> (Step e a m b -> Iteratee e a' m b') -> Step e a m b -> Iteratee e a' m b'
+ Data.Enumerator: catchError :: (Monad m) => Iteratee e a m b -> (e -> Iteratee e a m b) -> Iteratee e a m b
+ Data.Enumerator: liftFoldL :: (Monad m) => (b -> a -> b) -> b -> Iteratee e a m b
+ Data.Enumerator: liftFoldL' :: (Monad m) => (b -> a -> b) -> b -> Iteratee e a m b
+ Data.Enumerator: liftFoldM :: (Monad m) => (b -> a -> m b) -> b -> Iteratee e a m b
+ Data.Enumerator: liftTrans :: (Monad m, MonadTrans t, Monad (t m)) => Iteratee e a m b -> Iteratee e a (t m) b

Files

Examples/cat.hs view
@@ -105,11 +105,9 @@ 		then enumHandle 1 stdin 		else concatEnums (Prelude.map enumFile args) 	-	-- This line looks a bit weird, because the (>>==) causes a visual-	-- "flow" from the iteratee to the enumerator. However, data is-	-- actually being sent from the enumerator to the iteratee. It's-	-- better to think of it in terms of continuation passing.-	res <- run (iterHandle stdout >>== enum)+	-- 'run' sends an EOF to an iteratee and returns its output, which+	-- is either a 'Yield' or an 'Error'.+	res <- run (enum $$ iterHandle stdout) 	 	-- Finally, 'run' has returned either an error or the iteratee's 	-- result. 'iterHandle' doesn't return a useful result, so as long
+ Examples/enumerator-wcl.hs view
@@ -0,0 +1,22 @@+module Main (main) where+import Data.Enumerator+import Data.Enumerator.IO+import qualified Data.ByteString as B+import qualified Data.ByteString.Char8 as B8+import System.IO+import System.Environment++iterLines :: Monad m => Iteratee e B.ByteString m Integer+iterLines = continue (step 0) where+	step acc EOF = yield acc EOF+	step acc (Chunks xs) = continue $ step $! foldl foldStep acc xs+	foldStep acc bytes = acc + countChar '\n' bytes++countChar :: Char -> B.ByteString -> Integer+countChar c = B8.foldl (\acc c' -> if c' == c then acc + 1 else acc) 0++main :: IO ()+main = do+	filename:_ <- getArgs+	h <- openBinaryFile filename ReadMode+	run (iterLines >>== enumHandle 4096 h) >>= print
+ Examples/iteratee-wcl.hs view
@@ -0,0 +1,24 @@+module Main (main) where+import Data.Iteratee+import Data.Iteratee.IO+import Data.Iteratee.WrappedByteString+import Data.Word (Word8)+import qualified Data.ByteString as B+import qualified Data.ByteString.Char8 as B8+import System.IO+import System.Environment++iterLines :: Monad m => IterateeG WrappedByteString Word8 m Integer+iterLines = IterateeG (step 0) where+	step acc s@(EOF _) = return $ Done acc s+	step acc (Chunk wrapped) = return $ Cont (IterateeG (step $! acc')) Nothing where+		acc' = acc + countChar '\n' (unWrap wrapped)++countChar :: Char -> B.ByteString -> Integer+countChar c = B8.foldl (\acc c' -> if c' == c then acc + 1 else acc) 0++main :: IO ()+main = do+	filename:_ <- getArgs+	h <- openBinaryFile filename ReadMode+	enumHandle h iterLines >>= run >>= print
+ Examples/lazy-bytestring-wcl.hs view
@@ -0,0 +1,16 @@+import qualified Data.ByteString.Lazy as B+import qualified Data.ByteString.Lazy.Char8 as B8+import System.IO+import System.Environment++countChar :: Char -> B.ByteString -> Integer+countChar c = B8.foldl' (\acc c' -> if c' == c then acc + 1 else acc) 0++countHandle :: Handle -> IO Integer+countHandle h = fmap (countChar '\n') (B.hGetContents h)++main :: IO ()+main = do+	filename:_ <- getArgs+	h <- openBinaryFile filename ReadMode+	countHandle h >>= print
+ Examples/strict-bytestring-wcl.hs view
@@ -0,0 +1,21 @@+import qualified Data.ByteString as B+import qualified Data.ByteString.Char8 as B8+import System.IO+import System.Environment++countChar :: Char -> B.ByteString -> Integer+countChar c = B8.foldl' (\acc c' -> if c' == c then acc + 1 else acc) 0++countHandle :: Handle -> IO Integer+countHandle h = loop 0 where+	loop acc = do+		bytes <- B.hGet h 4096+		if B.null bytes+			then return acc+			else let acc' = acc + countChar '\n' bytes in loop $! acc'++main :: IO ()+main = do+	filename:_ <- getArgs+	h <- openBinaryFile filename ReadMode+	countHandle h >>= print
Examples/wc.hs view
@@ -34,16 +34,17 @@ iterBytes :: Monad m => Iteratee e B.ByteString m Integer iterBytes = continue (step 0) where 	step acc EOF = yield acc EOF-	step acc (Chunks xs) = continue $ step (foldl' foldStep acc xs)+	step acc (Chunks xs) = continue $ step $! foldl' foldStep acc xs 	foldStep acc bytes = acc + toInteger (B.length bytes)  -- iterLines is similar, except it only counts newlines ('\n')+--+-- Because it's basically the same as 'iterBytes', we use it to demonstrate+-- the 'liftFoldL\'' helper function.  iterLines :: Monad m => Iteratee e B.ByteString m Integer-iterLines = continue (step 0) where-	step acc EOF = yield acc EOF-	step acc (Chunks xs) = continue $ step (foldl' foldStep acc xs)-	foldStep acc bytes = acc + countChar '\n' bytes+iterLines = liftFoldL' step 0 where+	step acc bytes = acc + countChar '\n' bytes 	countChar c = B8.foldl (\acc c' -> if c' == c then acc + 1 else acc) 0  -- iterChars is a bit more complicated. It has to decode the input (for now,@@ -58,7 +59,7 @@ 	step accT chunk = case chunk of 		EOF -> let (extra, acc) = accT in yield acc (Chunks [extra]) 		(Chunks xs) -> case foldl' foldStep (Just accT) xs of-			Just accT' -> continue $ step accT'+			Just accT' -> continue $ step $! accT' 			Nothing -> throwError (E.SomeException (E.ErrorCall "Invalid UTF-8")) 	 	-- The 'decodeUtf8' function is complicated, and defined later, but@@ -87,7 +88,7 @@ 		putStr $ filename ++ ": " 		 		-- see cat.hs for commented implementation of 'Data.Enumerator.IO.enumFile'-		eitherStat <- run (iter >>== enumFile filename)+		eitherStat <- run (enumFile filename $$ iter) 		putStrLn $ case eitherStat of 			Left err -> "ERROR: " ++ show err 			Right stat -> show stat
enumerator.cabal view
@@ -1,5 +1,5 @@ name: enumerator-version: 0.1+version: 0.1.1 synopsis: Implementation of Oleg Kiselyov's left-fold enumerators license: MIT license-file: license.txt
hs/Data/Enumerator.hs view
@@ -25,12 +25,20 @@ 	, yield 	, continue 	, throwError+	, catchError 	, liftI 	, (>>==) 	, (==<<)+	, ($$)+	, (>==>)+	, (<==<) 	  -- ** Iteratees 	, consume 	, isEOF+	, liftTrans+	, liftFoldL+	, liftFoldL'+	, liftFoldM 	  -- ** Enumerators 	, enumEOF 	, enumList@@ -63,6 +71,8 @@ import Control.Monad (liftM, ap) import qualified Control.Monad.IO.Class as MIO import qualified Control.Monad.Trans.Class as MT+import qualified Data.List as DataList+import Control.Monad (foldM) import qualified Control.Exception as E import Prelude hiding (span) import qualified Prelude as Prelude@@ -165,6 +175,16 @@ instance MIO.MonadIO m => MIO.MonadIO (Iteratee e a m) where 	liftIO = MT.lift . MIO.liftIO 	{-# INLINE liftIO #-}+-- | Lift an 'Iteratee' onto a monad transformer, re-wrapping the+-- 'Iteratee'&#x2019;s inner monadic values.+liftTrans :: (Monad m, MT.MonadTrans t, Monad (t m)) =>+             Iteratee e a m b -> Iteratee e a (t m) b+liftTrans iter = Iteratee $ do+	step <- MT.lift $ runIteratee iter+	return $ case step of+		Yield x cs -> Yield x cs+		Error err -> Error err+		Continue k -> Continue (liftTrans . k) -- | @returnI x = Iteratee (return x)@ returnI :: Monad m => Step e a m b -> Iteratee e a m b returnI = Iteratee . return@@ -189,6 +209,12 @@ liftI :: Monad m => (Stream a -> Step e a m b) -> Iteratee e a m b liftI k = continue $ returnI . k {-# INLINE liftI #-}+catchError :: Monad m => Iteratee e a m b -> (e -> Iteratee e a m b) -> Iteratee e a m b+catchError iter h = Iteratee $ do+	step <- runIteratee iter+	case step of+		Error err -> runIteratee (h err)+		_ -> return step -- | Equivalent to (>>=), but allows 'Iteratee's with different input types -- to be composed. (>>==) :: Monad m =>@@ -205,18 +231,68 @@ 	Iteratee e a' m b' (==<<) = flip (>>==) {-# INLINE (==<<) #-}++-- | @($$) = (==\<\<)@+--+-- This might be easier to read when passing a chain of iteratees to an+-- enumerator.+($$):: Monad m =>+	(Step e a m b -> Iteratee e a' m b') ->+	Iteratee e a m b ->+	Iteratee e a' m b'+($$) = (==<<)+{-# INLINE ($$) #-}+-- | @(>==>) e1 e2 s = e1 s >>== e2@+(>==>) :: Monad m =>+	Enumerator e a m b ->+	(Step e a m b -> Iteratee e a' m b') ->+	Step e a m b ->+	Iteratee e a' m b'+(>==>) e1 e2 s = e1 s >>== e2+{-# INLINE (>==>) #-}++-- | @(\<==\<) = flip (>==>)@+(<==<) :: Monad m =>+	(Step e a m b -> Iteratee e a' m b') ->+	Enumerator e a m b ->+	Step e a m b ->+	Iteratee e a' m b'+(<==<) = flip (>==>)+{-# INLINE (<==<) #-} -- | Consume all input until 'EOF', then return consumed input as a list. consume :: Monad m => Iteratee e a m [a]-consume = liftI $ step [] where+consume = liftI $ step id where 	step acc chunk = case chunk of 		Chunks [] -> Continue $ returnI . step acc-		Chunks xs -> Continue $ returnI . (step $ acc ++ xs)-		EOF -> Yield acc EOF+		Chunks xs -> Continue $ returnI . (step $ acc . (xs ++))+		EOF -> Yield (acc []) EOF -- | Return 'True' if the next 'Stream' is 'EOF'. isEOF :: Monad m => Iteratee e a m Bool isEOF = liftI $ \c -> case c of 	EOF -> Yield True c 	_   -> Yield False c+-- | Lifts a pure left fold into an iteratee.+liftFoldL :: Monad m => (b -> a -> b) -> b -> Iteratee e a m b+liftFoldL f = liftI . step where+	step acc chunk = case chunk of+		Chunks [] -> Continue $ returnI . step acc+		Chunks xs -> Continue $ returnI . step (Prelude.foldl f acc xs)+		EOF -> Yield acc EOF+-- | As 'liftFoldL', but strict in its accumulator.+liftFoldL' :: Monad m => (b -> a -> b) -> b -> Iteratee e a m b+liftFoldL' f = liftI . step where+	fold = DataList.foldl' f+	step acc chunk = case chunk of+		Chunks [] -> Continue $ returnI . step acc+		Chunks xs -> Continue $ returnI . (step $! fold acc xs)+		EOF -> Yield acc EOF+-- | Lifts a monadic left fold into an iteratee.+liftFoldM :: Monad m => (b -> a -> m b) -> b -> Iteratee e a m b+liftFoldM f = continue . step where+	step acc chunk = case chunk of+		Chunks [] -> continue $ step acc+		Chunks xs -> Iteratee $ liftM (Continue . step) (foldM f acc xs)+		EOF -> yield acc EOF -- | The most primitive enumerator; simply sends 'EOF'. The iteratee must -- either yield a value or throw an error continuing receiving 'EOF' will -- not terminate with any useful value.@@ -237,8 +313,8 @@ enumList _ _ step = returnI step -- | Compose a list of 'Enumerator's using '(>>==)' concatEnums :: Monad m => [Enumerator e a m b] -> Enumerator e a m b-concatEnums [] s = returnI s-concatEnums (e:es) s = e s >>== concatEnums es+concatEnums = foldl (>==>) returnI+{-# INLINE concatEnums #-} -- | 'joinI' is used to &#x201C;flatten&#x201D; 'Enumeratee's into an -- 'Iteratee'. joinI :: Monad m => Iteratee e a m (Step e a' m b) -> Iteratee e a m b
hs/Data/Enumerator/IO.hs view
@@ -20,7 +20,6 @@ import Control.Monad.IO.Class (liftIO) import qualified Control.Exception as E import qualified Data.ByteString as B-import qualified Foreign as F import qualified System.IO as IO -- | Read bytes (in chunks of the given buffer size) from the handle, and -- stream them to an 'Iteratee'. If an exception occurs during file IO,@@ -29,19 +28,18 @@ enumHandle :: Integer -- ^ Buffer size            -> IO.Handle            -> Enumerator E.SomeException B.ByteString IO b-enumHandle bufferSize h = Iteratee . F.allocaBytes size' . loop where+enumHandle bufferSize h = Iteratee . loop where 	size' = fromInteger bufferSize 	loop (Continue k) = read' k-	loop step = const $ return step-	read' k p = do-		eitherN <- E.try $ IO.hGetBuf h p size'-		case eitherN of+	loop step = return step+	read' k = do+		eitherB <- E.try $ B.hGet h size'+		case eitherB of 			Left err -> return $ Error err-			Right 0 -> return $ Continue k-			Right n -> do-				bytes <- B.packCStringLen (p, n)+			Right bytes | B.null bytes -> return $ Continue k+			Right bytes -> do 				step <- runIteratee (k (Chunks [bytes]))-				loop step p+				loop step -- | Opens a file path in binary mode, and passes the handle to 'enumHandle'. -- The file will be closed when the 'Iteratee' finishes. enumFile :: FilePath -> Enumerator E.SomeException B.ByteString IO b