diff --git a/Examples/cat.hs b/Examples/cat.hs
--- a/Examples/cat.hs
+++ b/Examples/cat.hs
@@ -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
diff --git a/Examples/enumerator-wcl.hs b/Examples/enumerator-wcl.hs
new file mode 100644
--- /dev/null
+++ b/Examples/enumerator-wcl.hs
@@ -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
diff --git a/Examples/iteratee-wcl.hs b/Examples/iteratee-wcl.hs
new file mode 100644
--- /dev/null
+++ b/Examples/iteratee-wcl.hs
@@ -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
diff --git a/Examples/lazy-bytestring-wcl.hs b/Examples/lazy-bytestring-wcl.hs
new file mode 100644
--- /dev/null
+++ b/Examples/lazy-bytestring-wcl.hs
@@ -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
diff --git a/Examples/strict-bytestring-wcl.hs b/Examples/strict-bytestring-wcl.hs
new file mode 100644
--- /dev/null
+++ b/Examples/strict-bytestring-wcl.hs
@@ -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
diff --git a/Examples/wc.hs b/Examples/wc.hs
--- a/Examples/wc.hs
+++ b/Examples/wc.hs
@@ -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
diff --git a/enumerator.cabal b/enumerator.cabal
--- a/enumerator.cabal
+++ b/enumerator.cabal
@@ -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
diff --git a/hs/Data/Enumerator.hs b/hs/Data/Enumerator.hs
--- a/hs/Data/Enumerator.hs
+++ b/hs/Data/Enumerator.hs
@@ -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
diff --git a/hs/Data/Enumerator/IO.hs b/hs/Data/Enumerator/IO.hs
--- a/hs/Data/Enumerator/IO.hs
+++ b/hs/Data/Enumerator/IO.hs
@@ -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
