-- |
-- Module: Data.Enumerator
-- Copyright: 2010-2011 John Millikin
-- License: MIT
--
-- Maintainer: jmillikin@gmail.com
-- Portability: portable
--
-- Core enumerator types, and some useful primitives.
--
-- This module is intended to be imported qualified:
--
-- @
-- import qualified Data.Enumerator as E
-- @
module Data.Enumerator
	(
	
	-- * Types
	  Stream (..)
	, Iteratee (..)
	, Step (..)
	, Enumerator
	, Enumeratee
	
	-- * Primitives
	, returnI
	, continue
	, yield
	
	-- ** Operators
	, (>>==)
	, (==<<)
	, ($$)
	, (>==>)
	, (<==<)
	, (=$)
	, ($=)
	
	-- ** Running iteratees
	, run
	, run_
	
	-- ** Error handling
	, throwError
	, catchError
	
	-- * Miscellaneous
	, concatEnums
	, joinI
	, joinE
	, Data.Enumerator.sequence
	, enumEOF
	, checkContinue0
	, checkContinue1
	, checkDoneEx
	, checkDone
	, isEOF
	, tryIO
	
	-- ** Testing and debugging
	, printChunks
	, enumList
	
	-- * Legacy compatibility
	
	-- ** Obsolete
	, liftTrans
	, liftI
	, peek
	, Data.Enumerator.last
	, Data.Enumerator.length
	
	-- ** Aliases
	, Data.Enumerator.head
	, Data.Enumerator.drop
	, Data.Enumerator.dropWhile
	, Data.Enumerator.span
	, Data.Enumerator.break
	, consume
	, Data.Enumerator.foldl
	, Data.Enumerator.foldl'
	, foldM
	, Data.Enumerator.iterate
	, iterateM
	, Data.Enumerator.repeat
	, repeatM
	, Data.Enumerator.replicate
	, replicateM
	, generateM
	, Data.Enumerator.map
	, Data.Enumerator.mapM
	, Data.Enumerator.concatMap
	, concatMapM
	, Data.Enumerator.filter
	, filterM
	, liftFoldL
	, liftFoldL'
	, liftFoldM
	
	) where

import           Control.Applicative as A
import qualified Control.Exception as Exc
import qualified Control.Monad as CM
import           Control.Monad.IO.Class (MonadIO, liftIO)
import           Control.Monad.Trans.Class (MonadTrans, lift)
import           Data.Function (fix)
import           Data.List (genericLength, genericSplitAt)
import           Data.Monoid (Monoid, mempty, mappend, mconcat)
import           Data.Typeable ( Typeable, typeOf
                               , Typeable1, typeOf1
                               , mkTyConApp, mkTyCon)

import {-# SOURCE #-} qualified Data.Enumerator.List as EL

-- | A 'Stream' is a sequence of chunks generated by an 'Enumerator'.
--
-- @('Chunks' [])@ is used to indicate that a stream is still active, but
-- currently has no available data. Iteratees should ignore empty chunks.
data Stream a
	= Chunks [a]
	| EOF
	deriving (Show, Eq)

instance Monad Stream where
	return = Chunks . return
	Chunks xs >>= f = mconcat (fmap f xs)
	EOF >>= _ = EOF

instance Monoid (Stream a) where
	mempty = Chunks mempty
	mappend (Chunks xs) (Chunks ys) = Chunks (xs ++ ys)
	mappend _ _ = EOF

data Step a m b
	-- | The 'Iteratee' is capable of accepting more input. Note that more input
	-- is not necessarily required; the 'Iteratee' might be able to generate a
	-- value immediately if it receives 'EOF'.
	= Continue (Stream a -> Iteratee a m b)
	
	-- | The 'Iteratee' cannot receive any more input, and has generated a
	-- result. Included in this value is left-over input, which can be passed to
	-- composed 'Iteratee's.
	| Yield b (Stream a)
	
	-- | The 'Iteratee' encountered an error which prevents it from proceeding
	-- further.
	| Error Exc.SomeException

-- | The primary data type for this library, which consumes
-- input from a 'Stream' until it either generates a value or encounters
-- an error. Rather than requiring all input at once, an iteratee will
-- return 'Continue' when it is capable of processing more data.
--
-- In general, iteratees begin in the 'Continue' state. As each chunk is
-- passed to the continuation, the iteratee returns the next step:
-- 'Continue' for more data, 'Yield' when it's finished, or 'Error' to
-- abort processing.
newtype Iteratee a m b = Iteratee
	{ runIteratee :: m (Step a m b)
	}

instance Monad m => Monad (Iteratee a m) where
	return x = yield x (Chunks [])

	m0 >>= f = ($ m0) $ fix $
		\bind m -> Iteratee $ runIteratee m >>= \r1 ->
			case r1 of
				Continue k -> return (Continue (bind . k))
				Error err -> return (Error err)
				Yield x (Chunks []) -> runIteratee (f x)
				Yield x extra -> runIteratee (f x) >>= \r2 ->
					case r2 of
						Continue k -> runIteratee (k extra)
						Error err -> return (Error err)
						Yield x' _ -> return (Yield x' extra)

instance MonadTrans (Iteratee a) where
	lift m = Iteratee (m >>= runIteratee . return)

instance MonadIO m => MonadIO (Iteratee a m) where
	liftIO = lift . liftIO

-- | While 'Iteratee's consume data, enumerators generate it. Since
-- @'Iteratee'@ is an alias for @m ('Step' a m b)@, 'Enumerator's can
-- be considered step transformers of type
-- @'Step' a m b -> m ('Step' a m b)@.
--
-- 'Enumerator's typically read from an external source (parser, handle,
-- random generator, etc). They feed chunks into an 'Iteratee' until the
-- source runs out of data (triggering 'EOF') or the iteratee finishes
-- processing ('Yield's a value).
type Enumerator a m b = Step a m b -> Iteratee a m b

-- | In cases where an enumerator acts as both a source and sink, the resulting
-- type is named an 'Enumeratee'. Enumeratees have two input types,
-- &#x201c;outer a&#x201d; (@aOut@) and &#x201c;inner a&#x201d; (@aIn@).
type Enumeratee ao ai m b = Step ai m b -> Iteratee ao m (Step ai m b)

-- | Since: 0.4.8
instance Typeable1 Stream where
	typeOf1 _ = mkTyConApp tyCon [] where
		tyCon = mkTyCon "Data.Enumerator.Stream"

-- | Since: 0.4.6
instance (Typeable a, Typeable1 m) =>
	Typeable1 (Iteratee a m) where
		typeOf1 i = let
			tyCon = mkTyCon "Data.Enumerator.Iteratee"
			(a, m) = peel i
			
			peel :: Iteratee a m b -> (a, m ())
			peel = undefined
			
			in mkTyConApp tyCon [typeOf a, typeOf1 m]

-- | Since: 0.4.8
instance (Typeable a, Typeable1 m) =>
	Typeable1 (Step a m) where
		typeOf1 s = let
			tyCon = mkTyCon "Data.Enumerator.Step"
			(a, m) = peel s
			
			peel :: Step a m b -> (a, m ())
			peel = undefined
			
			in mkTyConApp tyCon [typeOf a, typeOf1 m]

instance Monad m => Functor (Iteratee a m) where
	fmap = CM.liftM

instance Monad m => A.Applicative (Iteratee a m) where
	pure = return
	(<*>) = CM.ap

instance Functor Stream where
	fmap f (Chunks xs) = Chunks (fmap f xs)
	fmap _ EOF = EOF

-- | Since: 0.4.5
instance A.Applicative Stream where
	pure = return
	(<*>) = CM.ap

-- | @'returnI' step = 'Iteratee' (return step)@
returnI :: Monad m => Step a m b -> Iteratee a m b
returnI step = Iteratee (return step)

-- | @'yield' x extra = 'returnI' ('Yield' x extra)@
--
-- WARNING: due to the current encoding of iteratees in this library,
-- careless use of the 'yield' primitive may violate the monad laws.
-- To prevent this, always make sure that an iteratee never yields
-- extra data unless it has received at least one input element.
--
-- More strictly, iteratees may not yield data that they did not
-- receive as input. Don't use 'yield' to &#x201c;inject&#x201d; elements
-- into the stream.
yield :: Monad m => b -> Stream a -> Iteratee a m b
yield x extra = returnI (Yield x extra)

-- | @'continue' k = 'returnI' ('Continue' k)@
continue :: Monad m => (Stream a -> Iteratee a m b) -> Iteratee a m b
continue k = returnI (Continue k)

-- | Run an iteratee until it finishes, and return either the final value
-- (if it succeeded) or the error (if it failed).
run :: Monad m => Iteratee a m b
    -> m (Either Exc.SomeException b)
run i = do
	mStep <- runIteratee $ enumEOF ==<< i
	case mStep of
		Error err -> return $ Left err
		Yield x _ -> return $ Right x
		Continue _ -> error "run: divergent iteratee"

-- | Like 'run', except errors are converted to exceptions and thrown.
-- Primarily useful for small scripts or other simple cases.
--
-- Since: 0.4.1
run_ :: Monad m => Iteratee a m b -> m b
run_ i = run i >>= either Exc.throw return

-- | @'throwError' exc = 'returnI' ('Error' ('Exc.toException' exc))@
throwError :: (Monad m, Exc.Exception e) => e -> Iteratee a m b
throwError exc = returnI (Error (Exc.toException exc))

-- | Runs the iteratee, and calls an exception handler if an 'Error' is
-- returned. By handling errors within the enumerator library, and requiring
-- all errors to be represented by 'Exc.SomeException', libraries with
-- varying error types can be easily composed.
--
-- WARNING: after a few rounds of "catchError doesn't work because X", this
-- function has grown into a horrible monster. I have no concept of what
-- unexpected behaviors lurk in its dark crevices. Users are strongly advised
-- to wrap all uses of @catchError@ with an appropriate @isolate@, such as
-- @Data.Enumerator.List.isolate@ or @Data.Enumerator.Binary.isolate@, which
-- will handle input framing even in the face of unexpected errors.
--
-- Within the error handler, it is difficult or impossible to know how much
-- input the original iteratee has consumed.
--
-- Since: 0.1.1
catchError :: Monad m
           => Iteratee a m b
           -> (Exc.SomeException -> Iteratee a m b)
           -> Iteratee a m b
catchError i h = go i where
	go iter = Iteratee $ do
		step <- runIteratee iter
		case step of
			Yield _ _ -> return step
			Error err -> runIteratee (h err)
			Continue k -> return (Continue (wrap k))
	
	wrap k EOF = Iteratee $ do
		res <- run (k EOF)
		case res of
			Left err -> runIteratee (enumEOF $$ h err)
			Right b -> return (Yield b EOF)
	
	wrap k stream = Iteratee $ do
		step <- runIteratee (k stream)
		case step of
			Yield _ _ -> return step
			Error err -> do
				step' <- runIteratee (h err)
				case step' of
					Continue k' -> runIteratee (k' stream)
					_ -> return step'
			Continue k' -> return (Continue (wrap k'))

infixl 1 >>==
infixr 1 ==<<
infixr 0 $$
infixr 1 >==>
infixr 1 <==<

-- | Equivalent to '(>>=)' for @m ('Step' a m b)@; allows 'Iteratee's with
-- different input types to be composed.

(>>==) :: Monad m
       => Iteratee a m b
       -> (Step a m b -> Iteratee a' m b')
       -> Iteratee a' m b'
i >>== f = Iteratee (runIteratee i >>= runIteratee . f)

-- | @'(==\<\<)' = flip '(\>\>==)'@
(==<<) :: Monad m
       => (Step a m b -> Iteratee a' m b')
       -> Iteratee a m b
       -> Iteratee a' m b'
(==<<) = flip (>>==)

-- | @'($$)' = '(==\<\<)'@
--
-- This might be easier to read when passing a chain of iteratees to an
-- enumerator.
--
-- Since: 0.1.1
($$) :: Monad m
     => (Step a m b -> Iteratee a' m b')
     -> Iteratee a m b
     -> Iteratee a' m b'
($$) = (==<<)

-- | @'(>==>)' e1 e2 s = e1 s '>>==' e2@
--
-- Since: 0.1.1
(>==>) :: Monad m
       => Enumerator a m b
       -> (Step a m b -> Iteratee a' m b')
       -> Step a m b
       -> Iteratee a' m b'
(>==>) e1 e2 s = e1 s >>== e2

-- | @'(\<==\<)' = flip '(>==>)'@
--
-- Since: 0.1.1

(<==<) :: Monad m
       => (Step a m b -> Iteratee a' m b')
       -> Enumerator a m b
       -> Step a m b
       -> Iteratee a' m b'
(<==<) = flip (>==>)

-- | Print chunks as they're received from the enumerator, optionally
-- printing empty chunks.
printChunks :: (MonadIO m, Show a)
            => Bool -- ^ Print empty chunks
            -> Iteratee a m ()
printChunks printEmpty = continue loop where
	loop (Chunks xs) = do
		let hide = null xs && not printEmpty
		CM.unless hide (liftIO (print xs))
		continue loop
	
	loop EOF = do
		liftIO (putStrLn "EOF")
		yield () EOF

-- | @'enumList' n xs@ enumerates /xs/ as a stream, passing /n/ inputs per
-- chunk.
--
-- Primarily useful for testing and debugging.
enumList :: Monad m => Integer -> [a] -> Enumerator a m b
enumList n = loop where
	loop xs (Continue k) | not (null xs) = let
		(s1, s2) = genericSplitAt n xs
		in k (Chunks s1) >>== loop s2
	loop _ step = returnI step


-- | Compose a list of 'Enumerator's using @'(>>==)'@
concatEnums :: Monad m => [Enumerator a m b]
            -> Enumerator a m b
concatEnums = Prelude.foldl (>==>) returnI

-- | 'joinI' is used to &#x201C;flatten&#x201D; 'Enumeratee's into an
-- 'Iteratee'.
joinI :: Monad m => Iteratee a m (Step a' m b)
      -> Iteratee a m b
joinI outer = outer >>= check where
	check (Continue k) = k EOF >>== \s -> case s of
		Continue _ -> error "joinI: divergent iteratee"
		_ -> check s
	check (Yield x _) = return x
	check (Error e) = throwError e

infixr 0 =$

-- | @enum =$ iter = 'joinI' (enum $$ iter)@
--
-- &#x201c;Wraps&#x201d; an iteratee /inner/ in an enumeratee /wrapper/.
-- The resulting iteratee will consume /wrapper/&#x2019;s input type and
-- yield /inner/&#x2019;s output type.
--
-- Note: if the inner iteratee yields leftover input when it finishes,
-- that extra will be discarded.
--
-- As an example, consider an iteratee that converts a stream of UTF8-encoded
-- bytes into a single 'TL.Text':
--
-- > consumeUTF8 :: Monad m => Iteratee ByteString m Text
--
-- It could be written with either 'joinI' or '(=$)':
--
-- > import Data.Enumerator.Text as ET
-- >
-- > consumeUTF8 = joinI (decode utf8 $$ ET.consume)
-- > consumeUTF8 = decode utf8 =$ ET.consume
--
-- Since: 0.4.9
(=$) :: Monad m => Enumeratee ao ai m b -> Iteratee ai m b -> Iteratee ao m b
enum =$ iter = joinI (enum $$ iter)

-- | Flatten an enumerator/enumeratee pair into a single enumerator.
joinE :: Monad m
      => Enumerator ao m (Step ai m b)
      -> Enumeratee ao ai m b
      -> Enumerator ai m b
joinE enum enee s = Iteratee $ do
	step <- runIteratee (enumEOF $$ enum $$ enee s)
	case step of
		Error err -> return (Error err)
		Yield x _ -> return x
		Continue _ -> error "joinE: divergent iteratee"

infixr 0 $=

-- | @enum $= enee = 'joinE' enum enee@
--
-- &#x201c;Wraps&#x201d; an enumerator /inner/ in an enumeratee /wrapper/.
-- The resulting enumerator will generate /wrapper/&#x2019;s output type.
--
-- As an example, consider an enumerator that yields line character counts
-- for a text file (e.g. for source code readability checking):
--
-- > enumFileCounts :: FilePath -> Enumerator Int IO b
--
-- It could be written with either 'joinE' or '($=)':
--
-- > import Data.Text as T
-- > import Data.Enumerator.List as EL
-- > import Data.Enumerator.Text as ET
-- >
-- > enumFileCounts path = joinE (enumFile path) (EL.map T.length)
-- > enumFileCounts path = enumFile path $= EL.map T.length
--
-- Since: 0.4.9
($=) :: Monad m
     => Enumerator ao m (Step ai m b)
     -> Enumeratee ao ai m b
     -> Enumerator ai m b
($=) = joinE

-- | Feeds outer input elements into the provided iteratee until it yields
-- an inner input, passes that to the inner iteratee, and then loops.
sequence :: Monad m => Iteratee ao m ai
         -> Enumeratee ao ai m b
sequence i = loop where
	loop = checkDone check
	check k = isEOF >>= \f -> if f
		then yield (Continue k) EOF
		else step k
	step k = i >>= \v -> k (Chunks [v]) >>== loop

-- | Sends 'EOF' to its iteratee. Most clients should use 'run' or 'run_'
-- instead.
enumEOF :: Monad m => Enumerator a m b
enumEOF (Yield x _) = yield x EOF
enumEOF (Error err) = throwError err
enumEOF (Continue k) = k EOF >>== check where
	check (Continue _) = error "enumEOF: divergent iteratee"
	check s = enumEOF s

-- | A common pattern in 'Enumeratee' implementations is to check whether
-- the inner 'Iteratee' has finished, and if so, to return its output.
-- 'checkDone' passes its parameter a continuation if the 'Iteratee'
-- can still consume input, or yields otherwise.
--
-- Since: 0.4.3
checkDoneEx :: Monad m =>
	Stream a' ->
	((Stream a -> Iteratee a m b) -> Iteratee a' m (Step a m b)) ->
	Enumeratee a' a m b
checkDoneEx _     f (Continue k) = f k
checkDoneEx extra _ step         = yield step extra

-- | @'checkDone' = 'checkDoneEx' ('Chunks' [])@
--
-- Use this for enumeratees which do not have an input buffer.
checkDone :: Monad m =>
	((Stream a -> Iteratee a m b) -> Iteratee a' m (Step a m b)) ->
	Enumeratee a' a m b
checkDone = checkDoneEx (Chunks [])

-- | Check whether a stream has reached EOF. Most clients should use
-- 'Data.Enumerator.List.head' instead.
isEOF :: Monad m => Iteratee a m Bool
isEOF = continue $ \s -> case s of
	EOF -> yield True s
	_ -> yield False s

-- | Try to run an IO computation. If it throws an exception, the exception
-- is caught and converted into an {\tt Error}.
--
-- Since: 0.4.9
tryIO :: MonadIO m => IO b -> Iteratee a m b
tryIO io = Iteratee $ do
	tried <- liftIO (Exc.try io)
	return $ case tried of
		Right b -> Yield b (Chunks [])
		Left err -> Error err

-- | A common pattern in 'Enumerator' implementations is to check whether
-- the inner 'Iteratee' has finished, and if so, to return its output.
-- 'checkContinue0' passes its parameter a continuation if the 'Iteratee'
-- can still consume input; if not, it returns the iteratee's step.
--
-- The type signature here is a bit crazy, but it's actually very easy to
-- use. Take this code:
--
-- > repeat :: Monad m => a -> Enumerator a m b
-- > repeat x = loop where
-- > 	loop (Continue k) = k (Chunks [x]) >>== loop
-- > 	loop step = returnI step
--
-- And rewrite it without the boilerplate:
--
-- > repeat :: Monad m => a -> Enumerator a m b
-- > repeat x = checkContinue0 $ \loop k -> k (Chunks [x] >>== loop
--
-- Since: 0.4.9
checkContinue0 :: Monad m
               => (Enumerator a m b
                -> (Stream a -> Iteratee a m b)
                -> Iteratee a m b)
               -> Enumerator a m b
checkContinue0 inner = loop where
	loop (Continue k) = inner loop k
	loop step = returnI step


-- | Like 'checkContinue0', but allows each loop step to use a state value:
--
-- > iterate :: Monad m => (a -> a) -> a -> Enumerator a m b
-- > iterate f = checkContinue1 $ \loop a k -> k (Chunks [a]) >>== loop (f a)
--
-- Since: 0.4.9
checkContinue1 :: Monad m
               => ((s1 -> Enumerator a m b)
                -> s1
                -> (Stream a -> Iteratee a m b)
                -> Iteratee a m b)
               -> s1
               -> Enumerator a m b
checkContinue1 inner = loop where
	loop s (Continue k) = inner loop s k
	loop _ step = returnI step

-- | Lift an 'Iteratee' onto a monad transformer, re-wrapping the
-- 'Iteratee'&#x2019;s inner monadic values.
--
-- Since: 0.1.1
liftTrans :: (Monad m, MonadTrans t, Monad (t m)) =>
             Iteratee a m b -> Iteratee a (t m) b
liftTrans iter = Iteratee $ do
	step <- lift (runIteratee iter)
	return $ case step of
		Yield x cs -> Yield x cs
		Error err -> Error err
		Continue k -> Continue (liftTrans . k)

{-# DEPRECATED liftI "Use 'Data.Enumerator.continue' instead" #-}

-- | Deprecated in 0.4.5: use 'Data.Enumerator.continue' instead
liftI :: Monad m => (Stream a -> Step a m b)
      -> Iteratee a m b
liftI k = continue (returnI . k)

-- | Peek at the next element in the stream, or 'Nothing' if the stream
-- has ended.
peek :: Monad m => Iteratee a m (Maybe a)
peek = continue loop where
	loop (Chunks []) = continue loop
	loop chunk@(Chunks (x:_)) = yield (Just x) chunk
	loop EOF = yield Nothing EOF

-- | Get the last element in the stream, or 'Nothing' if the stream
-- has ended.
--
-- Consumes the entire stream.
last :: Monad m => Iteratee a m (Maybe a)
last = continue (loop Nothing) where
	loop ret (Chunks xs) = continue . loop $ case xs of
		[] -> ret
		_ -> Just (Prelude.last xs)
	loop ret EOF = yield ret EOF

-- | Get how many elements remained in the stream.
--
-- Consumes the entire stream.
length :: Monad m => Iteratee a m Integer
length = continue (loop 0) where
	len = genericLength
	loop n (Chunks xs) = continue (loop (n + len xs))
	loop n EOF = yield n EOF

{-# DEPRECATED head "Use 'Data.Enumerator.List.head' instead" #-}
-- | Deprecated in 0.4.5: use 'Data.Enumerator.List.head' instead
head :: Monad m => Iteratee a m (Maybe a)
head = EL.head

{-# DEPRECATED drop "Use 'Data.Enumerator.List.drop' instead" #-}
-- | Deprecated in 0.4.5: use 'Data.Enumerator.List.drop' instead
drop :: Monad m => Integer -> Iteratee a m ()
drop = EL.drop

{-# DEPRECATED dropWhile "Use 'Data.Enumerator.List.dropWhile' instead" #-}
-- | Deprecated in 0.4.5: use 'Data.Enumerator.List.dropWhile' instead
dropWhile :: Monad m => (a -> Bool) -> Iteratee a m ()
dropWhile = EL.dropWhile

{-# DEPRECATED span "Use 'Data.Enumerator.List.takeWhile' instead" #-}
-- | Deprecated in 0.4.5: use 'Data.Enumerator.List.takeWhile' instead
span :: Monad m => (a -> Bool) -> Iteratee a m [a]
span = EL.takeWhile

{-# DEPRECATED break "Use 'Data.Enumerator.List.takeWhile' instead" #-}
-- | Deprecated in 0.4.5: use 'Data.Enumerator.List.takeWhile' instead
break :: Monad m => (a -> Bool) -> Iteratee a m [a]
break p = EL.takeWhile (not . p)

{-# DEPRECATED consume "Use 'Data.Enumerator.List.consume' instead" #-}
-- | Deprecated in 0.4.5: use 'Data.Enumerator.List.consume' instead
consume :: Monad m => Iteratee a m [a]
consume = EL.consume

{-# DEPRECATED foldl "Use Data.Enumerator.List.fold instead" #-}
-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.fold' instead
--
-- Since: 0.4.5
foldl :: Monad m => (b -> a -> b) -> b -> Iteratee a m b
foldl step = continue . loop where
	fold = Prelude.foldl step
	loop acc stream = case stream of
		Chunks [] -> continue (loop acc)
		Chunks xs -> continue (loop (fold acc xs))
		EOF -> yield acc EOF

{-# DEPRECATED foldl' "Use Data.Enumerator.List.fold instead" #-}
-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.fold' instead
--
-- Since: 0.4.5
foldl' :: Monad m => (b -> a -> b) -> b -> Iteratee a m b
foldl' = EL.fold

{-# DEPRECATED foldM "Use Data.Enumerator.List.foldM instead" #-}
-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.foldM' instead
--
-- Since: 0.4.5
foldM :: Monad m => (b -> a -> m b) -> b -> Iteratee a m b
foldM = EL.foldM

{-# DEPRECATED iterate "Use Data.Enumerator.List.iterate instead" #-}
-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.iterate' instead
--
-- Since: 0.4.5
iterate :: Monad m => (a -> a) -> a -> Enumerator a m b
iterate = EL.iterate

{-# DEPRECATED iterateM "Use Data.Enumerator.List.iterateM instead" #-}
-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.iterateM' instead
--
-- Since: 0.4.5
iterateM :: Monad m => (a -> m a) -> a -> Enumerator a m b
iterateM = EL.iterateM

{-# DEPRECATED repeat "Use Data.Enumerator.List.repeat instead" #-}
-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.repeat' instead
--
-- Since: 0.4.5
repeat :: Monad m => a -> Enumerator a m b
repeat = EL.repeat

{-# DEPRECATED repeatM "Use Data.Enumerator.List.repeatM instead" #-}
-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.repeatM' instead
--
-- Since: 0.4.5
repeatM :: Monad m => m a -> Enumerator a m b
repeatM = EL.repeatM

{-# DEPRECATED replicate "Use Data.Enumerator.List.replicate instead" #-}
-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.replicate' instead
--
-- Since: 0.4.5
replicate :: Monad m => Integer -> a -> Enumerator a m b
replicate = EL.replicate

{-# DEPRECATED replicateM "Use Data.Enumerator.List.replicateM instead" #-}
-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.replicateM' instead
--
-- Since: 0.4.5
replicateM :: Monad m => Integer -> m a -> Enumerator a m b
replicateM = EL.replicateM

{-# DEPRECATED generateM "Use Data.Enumerator.List.generateM instead" #-}
-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.generateM' instead
--
-- Since: 0.4.5
generateM :: Monad m => m (Maybe a) -> Enumerator a m b
generateM = EL.generateM

{-# DEPRECATED map "Use Data.Enumerator.List.map instead" #-}
-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.map' instead
map :: Monad m => (ao -> ai) -> Enumeratee ao ai m b
map = EL.map

{-# DEPRECATED mapM "Use Data.Enumerator.List.mapM instead" #-}
-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.mapM' instead
--
-- Since: 0.4.3
mapM :: Monad m => (ao -> m ai) -> Enumeratee ao ai m b
mapM = EL.mapM

{-# DEPRECATED concatMap "Use Data.Enumerator.List.concatMap instead" #-}
-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.concatMap' instead
--
-- Since: 0.4.3
concatMap :: Monad m => (ao -> [ai]) -> Enumeratee ao ai m b
concatMap = EL.concatMap

{-# DEPRECATED concatMapM "Use Data.Enumerator.List.concatMapM instead" #-}
-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.concatMapM' instead
--
-- Since: 0.4.5
concatMapM :: Monad m => (ao -> m [ai]) -> Enumeratee ao ai m b
concatMapM = EL.concatMapM

{-# DEPRECATED filter "Use Data.Enumerator.List.filter instead" #-}
-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.filter' instead
--
-- Since: 0.4.5
filter :: Monad m => (a -> Bool) -> Enumeratee a a m b
filter = EL.filter

{-# DEPRECATED filterM "Use Data.Enumerator.List.filterM instead" #-}
-- | Deprecated in 0.4.8: use 'Data.Enumerator.List.filterM' instead
--
-- Since: 0.4.5
filterM :: Monad m => (a -> m Bool) -> Enumeratee a a m b
filterM = EL.filterM

{-# DEPRECATED liftFoldL "Use Data.Enumerator.List.fold instead" #-}
-- | Deprecated in 0.4.5: use 'Data.Enumerator.List.fold' instead
--
-- Since: 0.1.1
liftFoldL :: Monad m => (b -> a -> b) -> b
          -> Iteratee a m b
liftFoldL = Data.Enumerator.foldl

{-# DEPRECATED liftFoldL' "Use Data.Enumerator.List.fold instead" #-}
-- | Deprecated in 0.4.5: use 'Data.Enumerator.List.fold' instead
--
-- Since: 0.1.1
liftFoldL' :: Monad m => (b -> a -> b) -> b
           -> Iteratee a m b
liftFoldL' = EL.fold

{-# DEPRECATED liftFoldM "Use Data.Enumerator.List.foldM instead" #-}
-- | Deprecated in 0.4.5: use 'Data.Enumerator.List.foldM' instead
--
-- Since: 0.1.1
liftFoldM :: Monad m => (b -> a -> m b) -> b
          -> Iteratee a m b
liftFoldM = EL.foldM