diff --git a/enumerator.cabal b/enumerator.cabal
--- a/enumerator.cabal
+++ b/enumerator.cabal
@@ -1,5 +1,5 @@
 name: enumerator
-version: 0.4.16
+version: 0.4.17
 synopsis: Reliable, high-performance processing with left-fold enumerators
 license: MIT
 license-file: license.txt
@@ -131,7 +131,7 @@
 source-repository this
   type: bazaar
   location: https://john-millikin.com/branches/enumerator/0.4/
-  tag: enumerator_0.4.15
+  tag: enumerator_0.4.17
 
 library
   ghc-options: -Wall -O2
diff --git a/lib/Data/Enumerator.hs b/lib/Data/Enumerator.hs
--- a/lib/Data/Enumerator.hs
+++ b/lib/Data/Enumerator.hs
@@ -34,6 +34,7 @@
 	, (<==<)
 	, (=$)
 	, ($=)
+	, (=$=)
 	
 	-- * Error handling
 	, throwError
@@ -306,6 +307,30 @@
      -> Enumeratee ao ai m b
      -> Enumerator ai m b
 ($=) = joinE
+
+-- | Composes two enumeratees.
+--
+-- Note that if the inner enumeratee yields left-over input, this will be
+-- discarded.
+--
+-- Example: converting bytes into lower-case text:
+--
+-- > import Data.ByteString
+-- > import Data.Text
+-- > import Data.Enumerator.List as EnumList
+-- > import Data.Enumerator.Text
+-- >
+-- > decodeAndLower :: Monad m => Enumeratee ByteString Text m b
+-- > decodeAndLower = decode utf8 =$= EnumList.map toLower
+--
+-- Since: 0.4.17
+(=$=) :: Monad m
+      => Enumeratee a1 a2 m (Step a3 m b)
+      -> Enumeratee a2 a3 m b
+      -> Enumeratee a1 a3 m b
+e1 =$= e2 = \s -> joinI (e1 $$ e2 s)
+
+infixl 1 =$=
 
 -- | Feeds outer input elements into the provided iteratee until it yields
 -- an inner input, passes that to the inner iteratee, and then loops.
diff --git a/lib/Data/Enumerator/Text.hs b/lib/Data/Enumerator/Text.hs
--- a/lib/Data/Enumerator/Text.hs
+++ b/lib/Data/Enumerator/Text.hs
@@ -721,7 +721,7 @@
 	loop (Chunks []) = continue loop
 	loop (Chunks xs) = iter where
 		lazy = TL.fromChunks xs
-		(s1, s2) = TL.span p lazy
+		(s1, s2) = tlSpanBy p lazy
 		iter = if TL.null s2
 			then k (Chunks xs) >>== isolateWhile p
 			else k (toChunks s1) >>== (`yield` toChunks s2)
