diff --git a/Data/Conduit/Binary.hs b/Data/Conduit/Binary.hs
--- a/Data/Conduit/Binary.hs
+++ b/Data/Conduit/Binary.hs
@@ -396,3 +396,4 @@
                 f (S.index bs i)
                 loop (i + 1)
             | otherwise = return ()
+{-# INLINE [1] mapM_ #-}
diff --git a/Data/Conduit/Internal.hs b/Data/Conduit/Internal.hs
--- a/Data/Conduit/Internal.hs
+++ b/Data/Conduit/Internal.hs
@@ -50,6 +50,7 @@
     , sourceList
     , withUpstream
     , unwrapResumable
+    , Data.Conduit.Internal.enumFromTo
     ) where
 
 import Control.Applicative (Applicative (..))
@@ -555,21 +556,29 @@
 --
 -- Since 0.4.1
 mapOutput :: Monad m => (o1 -> o2) -> Pipe l i o1 u m r -> Pipe l i o2 u m r
-mapOutput f (HaveOutput p c o) = HaveOutput (mapOutput f p) c (f o)
-mapOutput f (NeedInput p c) = NeedInput (mapOutput f . p) (mapOutput f . c)
-mapOutput _ (Done r) = Done r
-mapOutput f (PipeM mp) = PipeM (liftM (mapOutput f) mp)
-mapOutput f (Leftover p i) = Leftover (mapOutput f p) i
+mapOutput f =
+    go
+  where
+    go (HaveOutput p c o) = HaveOutput (go p) c (f o)
+    go (NeedInput p c) = NeedInput (go . p) (go . c)
+    go (Done r) = Done r
+    go (PipeM mp) = PipeM (liftM (go) mp)
+    go (Leftover p i) = Leftover (go p) i
+{-# INLINE mapOutput #-}
 
 -- | Same as 'mapOutput', but use a function that returns @Maybe@ values.
 --
 -- Since 0.5.0
 mapOutputMaybe :: Monad m => (o1 -> Maybe o2) -> Pipe l i o1 u m r -> Pipe l i o2 u m r
-mapOutputMaybe f (HaveOutput p c o) = maybe id (\o' p' -> HaveOutput p' c o') (f o) (mapOutputMaybe f p)
-mapOutputMaybe f (NeedInput p c) = NeedInput (mapOutputMaybe f . p) (mapOutputMaybe f . c)
-mapOutputMaybe _ (Done r) = Done r
-mapOutputMaybe f (PipeM mp) = PipeM (liftM (mapOutputMaybe f) mp)
-mapOutputMaybe f (Leftover p i) = Leftover (mapOutputMaybe f p) i
+mapOutputMaybe f =
+    go
+  where
+    go (HaveOutput p c o) = maybe id (\o' p' -> HaveOutput p' c o') (f o) (mapOutputMaybe f p)
+    go (NeedInput p c) = NeedInput (go . p) (go . c)
+    go (Done r) = Done r
+    go (PipeM mp) = PipeM (liftM (go) mp)
+    go (Leftover p i) = Leftover (go p) i
+{-# INLINE mapOutputMaybe #-}
 
 -- | Apply a function to all the input values of a @Pipe@.
 --
@@ -584,6 +593,18 @@
 mapInput _ _  (Done r)           = Done r
 mapInput f f' (PipeM mp)         = PipeM (liftM (mapInput f f') mp)
 mapInput f f' (Leftover p i)     = maybe id (flip Leftover) (f' i) $ mapInput f f' p
+
+enumFromTo :: (Enum o, Eq o, Monad m)
+           => o
+           -> o
+           -> Pipe l i o u m ()
+enumFromTo start stop =
+    loop start
+  where
+    loop i
+        | i == stop = HaveOutput (Done ()) (return ()) i
+        | otherwise = HaveOutput (loop (succ i)) (return ()) i
+{-# INLINE enumFromTo #-}
 
 -- | Convert a list into a source.
 --
diff --git a/Data/Conduit/List.hs b/Data/Conduit/List.hs
--- a/Data/Conduit/List.hs
+++ b/Data/Conduit/List.hs
@@ -70,6 +70,7 @@
 import Data.Monoid (Monoid, mempty, mappend)
 import qualified Data.Foldable as F
 import Data.Conduit
+import qualified Data.Conduit.Internal as CI
 import Control.Monad (when, (<=<), liftM)
 import Control.Monad.Trans.Class (lift)
 
@@ -102,12 +103,8 @@
            => a
            -> a
            -> Producer m a
-enumFromTo start stop =
-    go start
-  where
-    go i
-        | i == stop = yield i
-        | otherwise = yield i >> go (succ i)
+enumFromTo x = CI.ConduitM . CI.enumFromTo x
+{-# INLINE enumFromTo #-}
 
 -- | Produces an infinite stream of repeated applications of f to x.
 iterate :: Monad m => (a -> a) -> a -> Producer m a
@@ -180,6 +177,18 @@
       -> Consumer a m ()
 mapM_ f = awaitForever $ lift . f
 
+srcMapM_ :: Monad m => Source m a -> (a -> m ()) -> m ()
+srcMapM_ (CI.ConduitM src) f =
+    go src
+  where
+    go (CI.Done ()) = return ()
+    go (CI.PipeM mp) = mp >>= go
+    go (CI.Leftover p ()) = go p
+    go (CI.HaveOutput p _ o) = f o >> go p
+    go (CI.NeedInput _ c) = go (c ())
+{-# INLINE srcMapM_ #-}
+{-# RULES "connect to mapM_" forall f src. src $$ mapM_ f = srcMapM_ src f #-}
+
 -- | Ignore a certain number of values in the stream. This function is
 -- semantically equivalent to:
 --
@@ -234,7 +243,16 @@
 -- Since 0.3.0
 map :: Monad m => (a -> b) -> Conduit a m b
 map f = awaitForever $ yield . f
+{-# INLINE [1] map #-}
 
+-- Since a Source never has any leftovers, fusion rules on it are safe.
+{-# RULES "source/map fusion $=" forall f src. src $= map f = mapFuseRight src f #-}
+{-# RULES "source/map fusion =$=" forall f src. src =$= map f = mapFuseRight src f #-}
+
+mapFuseRight :: Monad m => Source m a -> (a -> b) -> Source m b
+mapFuseRight (CI.ConduitM src) f = CI.ConduitM (CI.mapOutput f src)
+{-# INLINE mapFuseRight #-}
+
 {-
 
 It might be nice to include these rewrite rules, but they may have subtle
@@ -423,12 +441,42 @@
 filter :: Monad m => (a -> Bool) -> Conduit a m a
 filter f = awaitForever $ \i -> when (f i) (yield i)
 
+filterFuseRight :: Monad m => Source m a -> (a -> Bool) -> Source m a
+filterFuseRight (CI.ConduitM src) f =
+    CI.ConduitM (go src)
+  where
+    go (CI.Done ()) = CI.Done ()
+    go (CI.PipeM mp) = CI.PipeM (liftM go mp)
+    go (CI.Leftover p i) = CI.Leftover (go p) i
+    go (CI.HaveOutput p c o)
+        | f o = CI.HaveOutput (go p) c o
+        | otherwise = go p
+    go (CI.NeedInput p c) = CI.NeedInput (go . p) (go . c)
+-- Intermediate finalizers are dropped, but this is acceptable: the next
+-- yielded value would be demanded by downstream in any event, and that new
+-- finalizer will always override the existing finalizer.
+{-# RULES "source/filter fusion $=" forall f src. src $= filter f = filterFuseRight src f #-}
+{-# RULES "source/filter fusion =$=" forall f src. src =$= filter f = filterFuseRight src f #-}
+{-# INLINE filterFuseRight #-}
+
 -- | Ignore the remainder of values in the source. Particularly useful when
 -- combined with 'isolate'.
 --
 -- Since 0.3.0
 sinkNull :: Monad m => Consumer a m ()
 sinkNull = awaitForever $ \_ -> return ()
+{-# RULES "connect to sinkNull" forall src. src $$ sinkNull = srcSinkNull src #-}
+
+srcSinkNull :: Monad m => Source m a -> m ()
+srcSinkNull (CI.ConduitM src) =
+    go src
+  where
+    go (CI.Done ()) = return ()
+    go (CI.PipeM mp) = mp >>= go
+    go (CI.Leftover p ()) = go p
+    go (CI.HaveOutput p _ _) = go p
+    go (CI.NeedInput _ c) = go (c ())
+{-# INLINE srcSinkNull #-}
 
 -- | A source that outputs no values. Note that this is just a type-restricted
 -- synonym for 'mempty'.
diff --git a/conduit.cabal b/conduit.cabal
--- a/conduit.cabal
+++ b/conduit.cabal
@@ -1,5 +1,5 @@
 Name:                conduit
-Version:             1.0.10
+Version:             1.0.10.1
 Synopsis:            Streaming data processing library.
 Description:
     @conduit@ is a solution to the streaming data problem, allowing for production, transformation, and consumption of streams of data in constant memory. It is an alternative to lazy I\/O which guarantees deterministic resource handling, and fits in the same general solution space as @enumerator@\/@iteratee@ and @pipes@. For a tutorial, please visit <https://haskell.fpcomplete.com/user/snoyberg/library-documentation/conduit-overview>.
@@ -48,6 +48,7 @@
                        Data.Conduit.Lazy
                        Data.Conduit.Internal
                        Data.Conduit.Util
+                       -- Hiding while some details are worked out Data.Conduit.Lift
   Build-depends:       base                     >= 4.3          && < 5
                      , resourcet                >= 0.4.3        && < 0.5
                      , lifted-base              >= 0.1
diff --git a/test/main.hs b/test/main.hs
--- a/test/main.hs
+++ b/test/main.hs
@@ -5,6 +5,7 @@
 import Test.QuickCheck.Monadic (assert, monadicIO, run)
 
 import qualified Data.Conduit as C
+-- FIXME import qualified Data.Conduit.Lift as C
 import qualified Data.Conduit.Util as C
 import qualified Data.Conduit.Internal as CI
 import qualified Data.Conduit.List as CL
@@ -29,7 +30,7 @@
 import Control.Monad.IO.Class (liftIO)
 import Control.Monad.Trans.Class (lift)
 import Control.Monad.Trans.Writer (execWriter, tell, runWriterT)
-import Control.Monad.Trans.State (evalStateT, get, put)
+import Control.Monad.Trans.State (evalStateT, get, put, modify)
 import Control.Applicative (pure, (<$>), (<*>))
 import Data.Functor.Identity (Identity,runIdentity)
 import Control.Monad (forever)
@@ -1075,6 +1076,28 @@
             it "test1" $ verify test1L test1R "p1" "p2" "p3"
             -- FIXME this is broken it "test2" $ verify test2L test2R "p2" "p1" "p3"
             it "test3" $ verify test3L test3R "p2" "p3" "p1"
+
+    {- FIXME
+    describe "Data.Conduit.Lift" $ do
+        it "execStateC" $ do
+            let sink = C.execStateC 0 $ CL.mapM_ $ modify . (+)
+                src = mapM_ C.yield [1..10 :: Int]
+            res <- src C.$$ sink
+            res `shouldBe` sum [1..10]
+
+        it "execWriterT" $ do
+            let sink = C.execWriterC $ CL.mapM_ $ tell . return
+                src = mapM_ C.yield [1..10 :: Int]
+            res <- src C.$$ sink
+            res `shouldBe` [1..10]
+
+        it "runErrorT" $ do
+            let sink = C.runErrorC $ do
+                    x <- C.catchErrorC (lift $ throwError "foo") return
+                    return $ x ++ "bar"
+            res <- return () C.$$ sink
+            res `shouldBe` Right ("foobar" :: String)
+            -}
 
 it' :: String -> IO () -> Spec
 it' = it
