diff --git a/src/Data/Functor/Of.hs b/src/Data/Functor/Of.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Functor/Of.hs
@@ -0,0 +1,83 @@
+{-# LANGUAGE CPP, DeriveDataTypeable, DeriveTraversable, DeriveFoldable,
+       DeriveGeneric #-}
+module Data.Functor.Of where
+import Data.Monoid
+import Control.Applicative
+import Data.Traversable (Traversable)
+import Data.Foldable (Foldable)
+#if MIN_VERSION_base(4,8,0)
+import Data.Bifunctor
+#endif
+import Data.Data
+import Data.Typeable
+import GHC.Generics (Generic, Generic1)
+import Data.Functor.Classes
+
+-- | A left-strict pair; the base functor for streams of individual elements.
+data Of a b = !a :> b
+    deriving (Data, Eq, Foldable, Ord,
+              Read, Show, Traversable, Typeable, Generic, Generic1)
+infixr 5 :>
+
+instance (Monoid a, Monoid b) => Monoid (Of a b) where
+  mempty = mempty :> mempty
+  {-#INLINE mempty #-}
+  mappend (m :> w) (m' :> w') = mappend m m' :> mappend w w'
+  {-#INLINE mappend #-}
+
+instance Functor (Of a) where
+  fmap f (a :> x) = a :> f x
+  {-#INLINE fmap #-}
+  a <$ (b :> x)   = b :> a
+  {-#INLINE (<$) #-}
+
+#if MIN_VERSION_base(4,8,0)
+instance Bifunctor Of where
+  bimap f g (a :> b) = f a :> g b
+  {-#INLINE bimap #-}
+  first f   (a :> b) = f a :> b
+  {-#INLINE first #-}
+  second g  (a :> b) = a :> g b
+  {-#INLINE second #-}
+#endif
+
+instance Monoid a => Applicative (Of a) where
+  pure x = mempty :> x
+  {-#INLINE pure #-}
+  m :> f <*> m' :> x = mappend m m' :> f x
+  {-#INLINE (<*>) #-}
+  m :> x *> m' :> y  = mappend m m' :> y
+  {-#INLINE (*>) #-}
+  m :> x <* m' :> y  = mappend m m' :> x
+  {-#INLINE (<*) #-}
+
+instance Monoid a => Monad (Of a) where
+  return x = mempty :> x
+  {-#INLINE return #-}
+  m :> x >> m' :> y = mappend m m' :> y
+  {-#INLINE (>>) #-}
+  m :> x >>= f = let m' :> y = f x in mappend m m' :> y
+  {-#INLINE (>>=) #-}
+
+instance Show a => Show1 (Of a) where
+  liftShowsPrec = liftShowsPrec2 showsPrec showList
+
+instance Show2 Of where
+  liftShowsPrec2 spa _sla spb _slb p (a :> b) =
+    showParen (p > 5) $
+    spa 6 a .
+    showString " :> " .
+    spb 6 b
+
+instance Eq a => Eq1 (Of a) where
+  liftEq = liftEq2 (==)
+
+instance Ord a => Ord1 (Of a) where
+  liftCompare = liftCompare2 compare
+
+instance Eq2 Of where
+  liftEq2 eq1 eq2 (x :> y) (z :> w) = eq1 x z && eq2 y w
+
+instance Ord2 Of where
+  liftCompare2 comp1 comp2 (x :> y) (z :> w) =
+    comp1 x z `mappend` comp2 y w
diff --git a/src/Streaming.hs b/src/Streaming.hs
--- a/src/Streaming.hs
+++ b/src/Streaming.hs
@@ -1,4 +1,6 @@
-{-#LANGUAGE RankNTypes, CPP, Trustworthy #-}
+{-# LANGUAGE RankNTypes #-}
+
+{-# OPTIONS_GHC -Wall #-}
 module Streaming
    (
    -- * An iterable streaming monad transformer
@@ -19,8 +21,12 @@
 
    -- * Transforming streams
    maps,
+   mapsPost,
    mapsM,
+   mapsMPost,
    mapped,
+   mappedPost,
+   hoistUnexposed,
    distribute,
    groups,
 
@@ -40,12 +46,15 @@
 
    -- * Zipping, unzipping, separating and unseparating streams
    zipsWith,
+   zipsWith',
    zips,
    unzips,
    interleaves,
    separate,
    unseparate,
    decompose,
+   expand,
+   expandPost,
 
 
    -- * Eliminating a 'Stream'
@@ -61,10 +70,6 @@
    lazily,
    strictly,
 
-   -- * ResourceT help
-
-   bracketStream,
-
    -- * re-exports
    MFunctor(..),
    MMonad(..),
@@ -74,14 +79,7 @@
    Sum(..),
    Identity(..),
    Alternative((<|>)),
-   MonadThrow(..),
-   MonadResource(..),
-   MonadBase(..),
-   ResourceT(..),
-   runResourceT,
-#if MIN_VERSION_base(4,8,0)
    Bifunctor(..),
-#endif
 
    join,
    liftM,
@@ -102,13 +100,9 @@
 import Data.Functor.Compose
 import Data.Functor.Sum
 import Data.Functor.Identity
-
-import Control.Monad.Base
-import Control.Monad.Trans.Resource
-#if MIN_VERSION_base(4,8,0)
 import Data.Bifunctor
-#endif
 
+
 {- $stream
 
     The 'Stream' data type can be used to represent any effectful
@@ -133,7 +127,10 @@
 
 >   chunksOf     :: Int -> Stream f m r -> Stream (Stream f m) m r
 >   splitsAt     :: Int -> Stream f m r -> Stream f m (Stream f m r)
->   zipsWith     :: (forall x y. f x -> g y -> h (x, y)) -> Stream f m r -> Stream g m r -> Stream h m r
+>   zipsWith     :: (forall x y. f x -> g y -> h (x, y))
+                 -> Stream f m r -> Stream g m r -> Stream h m r
+>   zipsWith'    :: (forall x y p. (x -> y -> p) -> f x -> g y -> h p)
+                 -> Stream f m r -> Stream g m r -> Stream h m r
 >   intercalates :: Stream f m () -> Stream (Stream f m) m r -> Stream f m r
 >   unzips       :: Stream (Compose f g) m r ->  Stream f (Stream g m) r
 >   separate     :: Stream (Sum f g) m r -> Stream f (Stream g) m r  -- cp. partitionEithers
@@ -160,7 +157,6 @@
 -}
 
 {-| Map a stream to its church encoding; compare @Data.List.foldr@
-    This is the @safe_destroy@ exported by the @Internal@ module.
 
     Typical @FreeT@ operators can be defined in terms of @destroy@
     e.g.
diff --git a/src/Streaming/Internal.hs b/src/Streaming/Internal.hs
--- a/src/Streaming/Internal.hs
+++ b/src/Streaming/Internal.hs
@@ -1,6 +1,15 @@
-{-# LANGUAGE RankNTypes, StandaloneDeriving,DeriveDataTypeable, BangPatterns #-}
-{-# LANGUAGE UndecidableInstances, CPP, FlexibleInstances, MultiParamTypeClasses  #-}
-{-#LANGUAGE Trustworthy #-}
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE StandaloneDeriving #-}
+{-# LANGUAGE UndecidableInstances #-}
+
+{-# OPTIONS_GHC -Wall #-}
 module Streaming.Internal (
     -- * The free monad transformer
     -- $stream
@@ -34,6 +43,9 @@
     -- * Transforming streams
     , maps
     , mapsM
+    , mapsPost
+    , mapsMPost
+    , hoistUnexposed
     , decompose
     , mapsM_
     , run
@@ -51,24 +63,23 @@
   
     -- * Zipping and unzipping streams
     , zipsWith
+    , zipsWith'
     , zips
     , unzips
     , interleaves
     , separate
     , unseparate
+    , expand
+    , expandPost
 
   
     -- * Assorted Data.Functor.x help
-  
     , switch
   
-    -- * ResourceT help
-  
-    , bracketStream
-  
     -- *  For use in implementation
     , unexposed
     , hoistExposed
+    , hoistExposedPost
     , mapsExposed
     , mapsMExposed
     , destroyExposed
@@ -77,29 +88,19 @@
 
 import Control.Monad
 import Control.Monad.Trans
-import Control.Monad.Trans.Class
 import Control.Monad.Reader.Class
-import Control.Monad.Writer.Class
 import Control.Monad.State.Class
 import Control.Monad.Error.Class
-import Control.Monad.Cont.Class
 import Control.Applicative
-import Data.Foldable ( Foldable(..) )
-import Data.Traversable
+import Data.Function ( on )
 import Control.Monad.Morph
 import Data.Monoid (Monoid (..), (<>))
-import Data.Functor.Identity
-import Data.Data ( Data, Typeable )
+import Data.Data (Typeable)
 import Prelude hiding (splitAt)
 import Data.Functor.Compose
 import Data.Functor.Sum
+import Data.Functor.Classes
 import Control.Concurrent (threadDelay)
-import Control.Monad.Base
-import Control.Monad.Trans.Resource
-import Control.Monad.Catch (MonadCatch (..))
-import Control.Monad.Trans.Control
-
-
 {- $stream
 
     The 'Stream' data type is equivalent to @FreeT@ and can represent any effectful
@@ -127,26 +128,103 @@
 #if __GLASGOW_HASKELL__ >= 710
                   deriving (Typeable)
 #endif
-deriving instance (Show r, Show (m (Stream f m r))
-                  , Show (f (Stream f m r))) => Show (Stream f m r)
-deriving instance (Eq r, Eq (m (Stream f m r))
-                  , Eq (f (Stream f m r))) => Eq (Stream f m r)
-#if __GLASGOW_HASKELL__ >= 710
-deriving instance (Typeable f, Typeable m, Data r, Data (m (Stream f m r))
-                  , Data (f (Stream f m r))) => Data (Stream f m r)
-#endif
+
+-- The most obvious approach would probably be
+--
+-- s1 == s2 = eqUnexposed (unexposed s1) (unexposed s2)
+--
+-- but that seems to actually be rather hard (especially if performance
+-- matters even a little bit). Using `inspect` instead
+-- is nice and simple. The main downside is the rather weird-looking
+-- constraint it imposes. We *could* write
+--
+-- instance (Monad m, Eq r, Eq1 m, Eq1 f) => Eq (Stream f m r)
+--
+-- but there are an awful lot more Eq instances in the wild than
+-- Eq1 instances. Maybe some day soon we'll have implication constraints
+-- and everything will be beautiful.
+instance (Monad m, Eq (m (Either r (f (Stream f m r)))))
+         => Eq (Stream f m r) where
+  s1 == s2 = inspect s1 == inspect s2
+
+-- See the notes on Eq.
+instance (Monad m, Ord (m (Either r (f (Stream f m r)))))
+         => Ord (Stream f m r) where
+  compare = compare `on` inspect
+  (<) = (<) `on` inspect
+  (>) = (>) `on` inspect
+  (<=) = (<=) `on` inspect
+  (>=) = (>=) `on` inspect
+
+-- We could avoid a Show1 constraint for our Show1 instance by sneakily
+-- mapping everything to a single known type, but there's really no way
+-- to do that for Eq1 or Ord1.
+instance (Monad m, Functor f, Eq1 m, Eq1 f) => Eq1 (Stream f m) where
+  liftEq eq xs ys = liftEqExposed (unexposed xs) (unexposed ys)
+    where
+      liftEqExposed (Return x) (Return y) = eq x y
+      liftEqExposed (Effect m) (Effect n) = liftEq liftEqExposed m n
+      liftEqExposed (Step f) (Step g) = liftEq liftEqExposed f g
+      liftEqExposed _ _ = False
+
+instance (Monad m, Functor f, Ord1 m, Ord1 f) => Ord1 (Stream f m) where
+  liftCompare cmp xs ys = liftCmpExposed (unexposed xs) (unexposed ys)
+    where
+      liftCmpExposed (Return x) (Return y) = cmp x y
+      liftCmpExposed (Effect m) (Effect n) = liftCompare liftCmpExposed m n
+      liftCmpExposed (Step f) (Step g) = liftCompare liftCmpExposed f g
+      liftCmpExposed (Return _) _ = LT
+      liftCmpExposed _ (Return _) = GT
+      liftCmpExposed _ _ = error "liftCmpExposed: stream was exposed!"
+
+-- We could get a much less scary implementation using Show1, but
+-- Show1 instances aren't nearly as common as Show instances.
+--
+-- How does this
+-- funny-looking instance work?
+--
+-- We 'inspect' the stream to produce @m (Either r (Stream f m r))@.
+-- Then we work under @m@ to produce @m ShowSWrapper@. That's almost
+-- like producing @m String@, except that a @ShowSWrapper@ can be
+-- shown at any precedence. So the 'Show' instance for @m@ can show
+-- the contents at the correct precedence.
+instance (Monad m, Show r, Show (m ShowSWrapper), Show (f (Stream f m r)))
+         => Show (Stream f m r) where
+  showsPrec p xs = showParen (p > 10) $
+                     showString "Effect " . (showsPrec 11 $
+    flip fmap (inspect xs) $ \front ->
+      SS $ \d -> showParen (d > 10) $
+        case front of
+          Left r ->  showString "Return " . showsPrec 11 r
+          Right f -> showString "Step "   . showsPrec 11 f)
+
+instance (Monad m, Functor f, Show (m ShowSWrapper), Show (f ShowSWrapper))
+         => Show1 (Stream f m) where
+  liftShowsPrec sp sl p xs = showParen (p > 10) $
+                     showString "Effect " . (showsPrec 11 $
+    flip fmap (inspect xs) $ \front ->
+      SS $ \d -> showParen (d > 10) $
+        case front of
+          Left r ->  showString "Return " . sp 11 r
+          Right f -> showString "Step "   .
+                     showsPrec 11 (fmap (SS . (\str i -> liftShowsPrec sp sl i str)) f))
+
+newtype ShowSWrapper = SS (Int -> ShowS)
+instance Show ShowSWrapper where
+  showsPrec p (SS s) = s p
+
 instance (Functor f, Monad m) => Functor (Stream f m) where
   fmap f = loop where
     loop stream = case stream of
       Return r -> Return (f r)
       Effect m  -> Effect (do {stream' <- m; return (loop stream')})
-      Step f   -> Step (fmap loop f)
+      Step g -> Step (fmap loop g)
   {-# INLINABLE fmap #-}
   a <$ stream0 = loop stream0 where
     loop stream = case stream of
-      Return r -> Return a
-      Effect m  -> Effect (do {stream' <- m; return (loop stream')})
-      Step f    -> Step (fmap loop f)
+      Return _ -> Return a
+      Effect m -> Effect (do {stream' <- m; return (loop stream')})
+      Step f -> Step (fmap loop f)
   {-# INLINABLE (<$) #-}  
 
 instance (Functor f, Monad m) => Monad (Stream f m) where
@@ -155,7 +233,7 @@
   stream1 >> stream2 = loop stream1 where
     loop stream = case stream of
       Return _ -> stream2
-      Effect m  -> Effect (liftM loop m)
+      Effect m  -> Effect (fmap loop m)
       Step f   -> Step (fmap loop f)  
   {-# INLINABLE (>>) #-}
   -- (>>=) = _bind
@@ -165,7 +243,7 @@
     loop stream where
     loop stream0 = case stream0 of
       Step fstr -> Step (fmap loop fstr)
-      Effect m   -> Effect (liftM loop m)
+      Effect m   -> Effect (fmap loop m)
       Return r  -> f r
   {-# INLINABLE (>>=) #-}       
 
@@ -214,7 +292,7 @@
   empty = never
   {-#INLINE empty #-}
 
-  str <|> str' = zipsWith (liftA2 (,)) str str'
+  str <|> str' = zipsWith' liftA2 str str'
   {-#INLINE (<|>) #-}
 
 instance (Functor f, Monad m, Monoid w) => Monoid (Stream f m w) where
@@ -228,17 +306,18 @@
   mplus = (<|>)
 
 instance Functor f => MonadTrans (Stream f) where
-  lift = Effect . liftM Return
+  lift = Effect . fmap Return
   {-# INLINE lift #-}
 
 instance Functor f => MFunctor (Stream f) where
   hoist trans = loop  where
     loop stream = case stream of
       Return r  -> Return r
-      Effect m   -> Effect (trans (liftM loop m))
+      Effect m   -> Effect (trans (fmap loop m))
       Step f    -> Step (fmap loop f)
   {-# INLINABLE hoist #-}  
 
+
 instance Functor f => MMonad (Stream f) where
   embed phi = loop where
     loop stream = case stream of
@@ -248,58 +327,15 @@
   {-# INLINABLE embed #-}
 
 instance (MonadIO m, Functor f) => MonadIO (Stream f m) where
-  liftIO = Effect . liftM Return . liftIO
+  liftIO = Effect . fmap Return . liftIO
   {-# INLINE liftIO #-}
 
-instance (MonadBase b m, Functor f) => MonadBase b (Stream f m) where
-  liftBase  = effect . fmap return . liftBase
-  {-#INLINE liftBase #-}
-
-instance (MonadThrow m, Functor f) => MonadThrow (Stream f m) where
-  throwM = lift . throwM
-  {-#INLINE throwM #-}
-
-instance (MonadCatch m, Functor f) => MonadCatch (Stream f m) where
-  catch str f = go str
-    where
-    go p = case p of
-      Step f      -> Step (fmap go f)
-      Return  r   -> Return r
-      Effect  m   -> Effect (catch (do
-          p' <- m
-          return (go p'))
-       (\e -> return (f e)) )
-  {-#INLINABLE catch #-}
-     
-instance (MonadResource m, Functor f) => MonadResource (Stream f m) where
-  liftResourceT = lift . liftResourceT
-  {-#INLINE liftResourceT #-}
-
-
 instance (Functor f, MonadReader r m) => MonadReader r (Stream f m) where
   ask = lift ask
   {-# INLINE ask #-}
   local f = hoist (local f)
   {-# INLINE local #-}
-
--- instance (Functor f, MonadWriter w m) => MonadWriter w (Stream f m) where
---   tell = lift . tell
---   {-# INLINE tell #-}
--- --   listen (FreeT m) = FreeT $ liftM concat' $ listen (fmap listen `liftM` m)
---     where
---       concat' (Pure x, w) = Pure (x, w)
---       concat' (Free y, w) = Free $ fmap (second (w <>)) <$> y
---   pass m = FreeT . pass' . runFreeT . hoist  clean $ listen m
---     where
---       clean = pass . liftM (\x -> (x, const mempty))
---       pass' = join . liftM g
---       g (Pure ((x, f), w)) = tell (f w) >> return (Pure x)
---       g (Free f)           = return . Free . fmap (FreeT . pass' . runFreeT) $ f
--- #if MIN_VERSION_mtl(2,1,1)
---   writer w = lift (writer w)
---   {-# INLINE writer #-}
--- #endif
---
+ 
 instance (Functor f, MonadState s m) => MonadState s (Stream f m) where
   get = lift get
   {-# INLINE get #-}
@@ -314,36 +350,29 @@
   throwError = lift . throwError
   {-# INLINE throwError #-}
   str `catchError` f = loop str where
-    loop str = case str of
+    loop x = case x of
       Return r -> Return r
-      Effect m -> Effect $ liftM loop m `catchError` (return . f)
-      Step f -> Step (fmap loop f)
+      Effect m -> Effect $ fmap loop m `catchError` (return . f)
+      Step g -> Step (fmap loop g)
   {-# INLINABLE catchError #-}
 
-bracketStream :: (Functor f, MonadResource m) =>
-       IO a -> (a -> IO ()) -> (a -> Stream f m b) -> Stream f m b
-bracketStream alloc free inside = do
-        (key, seed) <- lift (allocate alloc free)
-        clean key (inside seed)
-  where
-    clean key = loop where
-      loop str = case str of
-        Return r -> Effect (release key >> return (Return r))
-        Effect m -> Effect (liftM loop m)
-        Step f   -> Step (fmap loop f)
-{-#INLINABLE bracketStream #-}
-
+{-| Map a stream to its church encoding; compare @Data.List.foldr@.
+    'destroyExposed' may be more efficient in some cases when
+    applicable, but it is less safe.
 
-{-| Map a stream directly to its church encoding; compare @Data.List.foldr@
+    @
+    destroy s construct eff done
+      = eff . iterT (return . construct . fmap eff) . fmap done $ s
+    @
 -}
 destroy
   :: (Functor f, Monad m) =>
      Stream f m r -> (f b -> b) -> (m b -> b) -> (r -> b) -> b
-destroy stream0 construct effect done = loop stream0 where
+destroy stream0 construct theEffect done = theEffect (loop stream0) where
   loop stream = case stream of
-    Return r -> done r
-    Effect m  -> effect (liftM loop m)
-    Step fs  -> construct (fmap loop fs)
+    Return r -> return (done r)
+    Effect m -> m >>= loop
+    Step fs -> return (construct (fmap (theEffect . loop) fs))
 {-# INLINABLE destroy #-}
 
 
@@ -368,16 +397,20 @@
      (f (Stream g m a) -> g (Stream g m a))
      -> Stream f m a -> Stream g m a                 -- maps
 
->>> :t \f -> streamFold return effect (effect . liftM wrap . f)
+>>> :t \f -> streamFold return effect (effect . fmap wrap . f)
 (Monad m, Functor f, Functor g) =>
      (f (Stream g m a) -> m (g (Stream g m a)))
      -> Stream f m a -> Stream g m a                 -- mapped
 
+@
+    streamFold done eff construct
+       = eff . iterT (return . construct . fmap eff) . fmap done
+@
 -}
 streamFold
   :: (Functor f, Monad m) =>
      (r -> b) -> (m b -> b) ->  (f b -> b) -> Stream f m r -> b
-streamFold done effect construct stream  = destroy stream construct effect done
+streamFold done theEffect construct stream  = destroy stream construct theEffect done
 {-#INLINE streamFold #-}
 
 {- | Reflect a church-encoded stream; cp. @GHC.Exts.build@
@@ -397,7 +430,7 @@
 > unfold inspect = id
 > Streaming.Prelude.unfoldr StreamingPrelude.next = id
 -}
-inspect :: (Functor f, Monad m) =>
+inspect :: Monad m =>
      Stream f m r -> m (Either r (f (Stream f m r)))
 inspect = loop where
   loop stream = case stream of
@@ -438,13 +471,13 @@
 maps phi = loop where
   loop stream = case stream of
     Return r  -> Return r
-    Effect m   -> Effect (liftM loop m)
+    Effect m   -> Effect (fmap loop m)
     Step f    -> Step (phi (fmap loop f))
 {-# INLINABLE maps #-}
 
 
-{- | Map layers of one functor to another with a transformation involving the base monad
-     @maps@ is more fundamental than @mapsM@, which is best understood as a convenience
+{- | Map layers of one functor to another with a transformation involving the base monad.
+     'maps' is more fundamental than @mapsM@, which is best understood as a convenience
      for effecting this frequent composition:
 
 > mapsM phi = decompose . maps (Compose . phi)
@@ -457,11 +490,58 @@
 mapsM phi = loop where
   loop stream = case stream of
     Return r  -> Return r
-    Effect m   -> Effect (liftM loop m)
-    Step f    -> Effect (liftM Step (phi (fmap loop f)))
+    Effect m   -> Effect (fmap loop m)
+    Step f    -> Effect (fmap Step (phi (fmap loop f)))
 {-# INLINABLE mapsM #-}
 
+{- | Map layers of one functor to another with a transformation. Compare
+     hoist, which has a similar effect on the 'monadic' parameter.
 
+> mapsPost id = id
+> mapsPost f . mapsPost g = mapsPost (f . g)
+> mapsPost f = mapsPost f
+
+
+     @mapsPost@ is essentially the same as 'maps', but it imposes a 'Functor' constraint on
+     its target functor rather than its source functor. It should be preferred if 'fmap'
+     is cheaper for the target functor than for the source functor.
+-}
+mapsPost :: forall m f g r. (Monad m, Functor g)
+         => (forall x. f x -> g x)
+         -> Stream f m r -> Stream g m r
+mapsPost phi = loop where
+  loop :: Stream f m r -> Stream g m r
+  loop stream = case stream of
+    Return r -> Return r
+    Effect m -> Effect (fmap loop m)
+    Step f -> Step $ fmap loop $ phi f
+{-# INLINABLE mapsPost #-}
+
+{- | Map layers of one functor to another with a transformation involving the base monad.
+     @mapsMPost@ is essentially the same as 'mapsM', but it imposes a 'Functor' constraint on
+     its target functor rather than its source functor. It should be preferred if 'fmap'
+     is cheaper for the target functor than for the source functor.
+
+     @mapsPost@ is more fundamental than @mapsMPost@, which is best understood as a convenience
+     for effecting this frequent composition:
+
+> mapsMPost phi = decompose . mapsPost (Compose . phi)
+
+     The streaming prelude exports the same function under the better name @mappedPost@,
+     which overlaps with the lens libraries.
+
+-}
+mapsMPost :: forall m f g r. (Monad m, Functor g)
+       => (forall x. f x -> m (g x))
+       -> Stream f m r -> Stream g m r
+mapsMPost phi = loop where
+  loop :: Stream f m r -> Stream g m r
+  loop stream = case stream of
+    Return r -> Return r
+    Effect m -> Effect (fmap loop m)
+    Step f -> Effect $ fmap (Step . fmap loop) (phi f)
+{-# INLINABLE mapsMPost #-}
+
 {-| Rearrange a succession of layers of the form @Compose m (f x)@.
 
    we could as well define @decompose@ by @mapsM@:
@@ -483,7 +563,7 @@
 decompose = loop where
   loop stream = case stream of
     Return r -> Return r
-    Effect m ->  Effect (liftM loop m)
+    Effect m ->  Effect (fmap loop m)
     Step (Compose mstr) -> Effect $ do
       str <- mstr
       return (Step (fmap loop str))
@@ -519,20 +599,21 @@
       Return r -> return r
       Effect m -> lift m >>= go0
       Step fstr -> do
-                f' <- fstr
-                go1 f'
+        f' <- fstr
+        go1 f'
     go1 f = case f of
       Return r -> return r
       Effect m     -> lift m >>= go1
       Step fstr ->  do
-                sep
-                f' <- fstr
-                go1 f'
+        _ <- sep
+        f' <- fstr
+        go1 f'
 {-# INLINABLE intercalates #-}
 
 {-| Specialized fold following the usage of @Control.Monad.Trans.Free@
 
 > iterTM alg = streamFold return (join . lift)
+> iterTM alg = iterT alg . hoist lift
 -}
 iterTM ::
   (Functor f, Monad m, MonadTrans t,
@@ -544,6 +625,7 @@
 {-| Specialized fold following the usage of @Control.Monad.Trans.Free@
 
 > iterT alg = streamFold return join alg
+> iterT alg = runIdentityT . iterTM (IdentityT . alg . fmap runIdentityT)
 -}
 iterT ::
   (Functor f, Monad m) => (f (m a) -> m a) -> Stream f m a -> m a
@@ -557,8 +639,8 @@
 concats  = loop where
   loop stream = case stream of
     Return r -> return r
-    Effect m  -> join $ lift (liftM loop m)
-    Step fs  -> join (fmap loop fs)
+    Effect m  -> lift m >>= loop
+    Step fs  -> fs >>= loop
 {-# INLINE concats #-}
 
 {-| Split a succession of layers after some number, returning a streaming or
@@ -590,7 +672,7 @@
     | n <= 0 = Return stream
     | otherwise = case stream of
         Return r       -> Return (Return r)
-        Effect m        -> Effect (liftM (loop n) m)
+        Effect m        -> Effect (fmap (loop n) m)
         Step fs        -> case n of
           0 -> Return (Step fs)
           _ -> Step (fmap (loop (n-1)) fs)
@@ -637,7 +719,7 @@
 chunksOf n0 = loop where
   loop stream = case stream of
     Return r  -> Return r
-    Effect m  -> Effect (liftM loop m)
+    Effect m  -> Effect (fmap loop m)
     Step fs   -> Step (Step (fmap (fmap loop . splitsAt (n0-1)) fs))
 {-# INLINABLE chunksOf #-}        
 
@@ -681,45 +763,78 @@
 cycles :: (Monad m, Functor f) =>  Stream f m () -> Stream f m r
 cycles = forever
 
+-- | A less-efficient version of 'hoist' that works properly even when its
+-- argument is not a monad morphism.
+--
+-- > hoistUnexposed = hoist . unexposed
+hoistUnexposed :: (Monad m, Functor f)
+               => (forall a. m a -> n a)
+               -> Stream f m r -> Stream f n r
+hoistUnexposed trans = loop where
+  loop = Effect . trans . inspectC (return . Return) (return . Step . fmap loop)
+{-# INLINABLE hoistUnexposed #-}
 
+-- A version of 'inspect' that takes explicit continuations.
+inspectC :: Monad m => (r -> m a) -> (f (Stream f m r) -> m a) -> Stream f m r -> m a
+inspectC f g = loop where
+  loop (Return r) = f r
+  loop (Step x) = g x
+  loop (Effect m) = m >>= loop
+{-# INLINE inspectC #-}
 
+-- | The same as 'hoist', but explicitly named to indicate that it
+-- is not entirely safe. In particular, its argument must be a monad
+-- morphism.
+hoistExposed :: (Functor m, Functor f) => (forall b. m b -> n b) -> Stream f m a -> Stream f n a
 hoistExposed trans = loop where
   loop stream = case stream of
     Return r  -> Return r
-    Effect m   -> Effect (trans (liftM loop m))
+    Effect m   -> Effect (trans (fmap loop m))
     Step f    -> Step (fmap loop f)
+{-# INLINABLE hoistExposed #-}
 
+-- | The same as 'hoistExposed', but with a 'Functor' constraint on
+-- the target rather than the source. This must be used only with
+-- a monad morphism.
+hoistExposedPost :: (Functor n, Functor f) => (forall b. m b -> n b) -> Stream f m a -> Stream f n a
+hoistExposedPost trans = loop where
+  loop stream = case stream of
+    Return r -> Return r
+    Effect m -> Effect (fmap loop (trans m))
+    Step f -> Step (fmap loop f)
+{-# INLINABLE hoistExposedPost #-}
+
+{-# DEPRECATED mapsExposed "Use maps instead." #-}
 mapsExposed :: (Monad m, Functor f)
      => (forall x . f x -> g x) -> Stream f m r -> Stream g m r
-mapsExposed phi = loop where
-  loop stream = case stream of
-    Return r  -> Return r
-    Effect m   -> Effect (liftM loop m)
-    Step f    -> Step (phi (fmap loop f))
+mapsExposed = maps
 {-# INLINABLE mapsExposed #-}
 
-mapsMExposed phi = loop where
-  loop stream = case stream of
-    Return r  -> Return r
-    Effect m   -> Effect (liftM loop m)
-    Step f    -> Effect (liftM Step (phi (fmap loop f)))
+{-# DEPRECATED mapsMExposed "Use mapsM instead." #-}
+mapsMExposed :: (Monad m, Functor f)
+     => (forall x . f x -> m (g x)) -> Stream f m r -> Stream g m r
+mapsMExposed = mapsM
 {-# INLINABLE mapsMExposed #-}
 
---     Map a stream directly to its church encoding; compare @Data.List.foldr@
---     It permits distinctions that should be hidden, as can be seen from
---     e.g.
---
--- isPure stream = destroy (const True) (const False) (const True)
---
---     and similar nonsense.  The crucial
---     constraint is that the @m x -> x@ argument is an /Eilenberg-Moore algebra/.
---     See Atkey "Reasoning about Stream Processing with Effects"
+{-| Map a stream directly to its church encoding; compare @Data.List.foldr@
+    It permits distinctions that should be hidden, as can be seen from
+    e.g.
 
+    @isPure stream = destroyExposed (const True) (const False) (const True)@
 
-destroyExposed stream0 construct effect done = loop stream0 where
+    and similar nonsense.  The crucial
+    constraint is that the @m x -> x@ argument is an /Eilenberg-Moore algebra/.
+    See Atkey, "Reasoning about Stream Processing with Effects"
+
+    When in doubt, use 'destroy' instead.
+-}
+destroyExposed
+  :: (Functor f, Monad m) =>
+     Stream f m r -> (f b -> b) -> (m b -> b) -> (r -> b) -> b
+destroyExposed stream0 construct theEffect done = loop stream0 where
   loop stream = case stream of
     Return r -> done r
-    Effect m  -> effect (liftM loop m)
+    Effect m  -> theEffect (fmap loop m)
     Step fs  -> construct (fmap loop fs)
 {-# INLINABLE destroyExposed #-}
 
@@ -793,31 +908,72 @@
 yields fr = Step (fmap Return fr)
 {-#INLINE yields #-}
 
+{-
+Note that if the first stream produces Return, we don't inspect
+(and potentially run effects from) the second stream. We used to
+do that. Aside from being (arguably) a bit strange, this also runs
+into a bit of trouble with MonadPlus laws. Most MonadPlus instances
+try to satisfy either left distribution or left catch. Let's first
+consider left distribution:
 
-zipsWith :: (Monad m, Functor f, Functor g, Functor h)
+(x <|> y) >>= k = (x >>= k) <|> (y >>= k)
+
+[xy_1, xy_2, xy_3, ..., xy_o | r_xy] >>= k
+=
+[x_1,  x_2,  x_3, ..., x_m | r_x] >>= k
+<|>
+[y_1,  y_2,  y_3, ..., y_n | r_y] >>= k
+
+x and y may have different lengths, and k may produce an utterly
+arbitrary stream from each result, so left distribution seems
+quite hopeless.
+
+Now let's consider left catch:
+
+zipsWith' liftA2 (return a) b = return a
+
+To satisfy this, we can't run any effects from the second stream
+if the first is finished.
+-}
+
+-- | Zip two streams together. The 'zipsWith'' function should generally
+-- be preferred for efficiency.
+zipsWith :: forall f g h m r. (Monad m, Functor h)
   => (forall x y . f x -> g y -> h (x,y))
   -> Stream f m r -> Stream g m r -> Stream h m r
-zipsWith phi s t = loop (s,t) where
-    loop (s1, s2) = Effect (go s1 s2)
-    go s1 s2 = do 
-      e  <- inspect s1
-      e' <- inspect s2
-      case (e,e') of
-        (Left r, _)              -> return (Return r)
-        (_, Left r)              -> return (Return r)
-        (Right fstr, Right gstr) -> return $ Step $ fmap loop (phi fstr gstr)
-{-# INLINABLE zipsWith #-} 
+zipsWith phi = zipsWith' $ \xyp fx gy -> (\(x,y) -> xyp x y) <$> phi fx gy
+{-# INLINABLE zipsWith #-}
+-- Somewhat surprisingly, GHC is *much* more willing to specialize
+-- zipsWith if it's defined in terms of zipsWith'. Fortunately, zipsWith'
+-- seems like a better function anyway, so I guess that's not a big problem.
 
+-- | Zip two streams together.
+zipsWith' :: forall f g h m r. Monad m
+  => (forall x y p . (x -> y -> p) -> f x -> g y -> h p)
+  -> Stream f m r -> Stream g m r -> Stream h m r
+zipsWith' phi = loop
+  where
+    loop :: Stream f m r -> Stream g m r -> Stream h m r
+    loop s t = case s of
+       Return r -> Return r
+       Step fs -> case t of
+         Return r -> Return r
+         Step gs -> Step $ phi loop fs gs
+         Effect n -> Effect $ fmap (loop s) n
+       Effect m -> Effect $ fmap (flip loop t) m
+{-# INLINABLE zipsWith' #-}
+
 zips :: (Monad m, Functor f, Functor g)
      => Stream f m r -> Stream g m r -> Stream (Compose f g) m r
-zips = zipsWith go where
-  go fx gy = Compose (fmap (\x -> fmap (\y -> (x,y)) gy) fx)
+zips = zipsWith' go where
+  go p fx gy = Compose (fmap (\x -> fmap (\y -> p x y) gy) fx)
 {-# INLINE zips #-} 
 
 
 
 {-| Interleave functor layers, with the effects of the first preceding
-    the effects of the second.
+    the effects of the second. When the first stream runs out, any remaining
+    effects in the second are ignored.
 
 > interleaves = zipsWith (liftA2 (,))
 
@@ -831,7 +987,7 @@
 interleaves
   :: (Monad m, Applicative h) =>
      Stream h m r -> Stream h m r -> Stream h m r
-interleaves = zipsWith (liftA2 (,))
+interleaves = zipsWith' liftA2
 {-# INLINE interleaves #-} 
 
 
@@ -916,7 +1072,36 @@
   return
 {-#INLINABLE unseparate #-}
 
+-- | If 'Of' had a @Comonad@ instance, then we'd have
+--
+-- @copy = expand extend@
+--
+-- See 'expandPost' for a version that requires a @Functor g@
+-- instance instead.
+expand :: (Monad m, Functor f)
+       => (forall a b. (g a -> b) -> f a -> h b)
+       -> Stream f m r -> Stream g (Stream h m) r
+expand ext = loop where
+  loop (Return r) = Return r
+  loop (Step f) = Effect $ Step $ ext (Return . Step) (fmap loop f)
+  loop (Effect m) = Effect $ Effect $ fmap (Return . loop) m
+{-# INLINABLE expand #-}
 
+-- | If 'Of' had a @Comonad@ instance, then we'd have
+--
+-- @copy = expandPost extend@
+--
+-- See 'expand' for a version that requires a @Functor f@ instance
+-- instead.
+expandPost :: (Monad m, Functor g)
+       => (forall a b. (g a -> b) -> f a -> h b)
+       -> Stream f m r -> Stream g (Stream h m) r
+expandPost ext = loop where
+  loop (Return r) = Return r
+  loop (Step f) = Effect $ Step $ ext (Return . Step . fmap loop) f
+  loop (Effect m) = Effect $ Effect $ fmap (Return . loop) m
+{-# INLINABLE expandPost #-}
+
 unzips :: (Monad m, Functor f, Functor g) =>
    Stream (Compose f g) m r ->  Stream f (Stream g m) r
 unzips str = destroyExposed
@@ -944,24 +1129,23 @@
 
   cleanL  :: (Monad m, Functor f, Functor g) =>
        Stream (Sum f g) m r -> Stream f m (Stream (Sum f g) m r)
-  cleanL = loop where
-    loop s = do
+  cleanL = go where
+    go s = do
      e <- lift $ inspect s
      case e of
       Left r           -> return (return r)
-      Right (InL fstr) -> wrap (fmap loop fstr)
+      Right (InL fstr) -> wrap (fmap go fstr)
       Right (InR gstr) -> return (wrap (InR gstr))
 
   cleanR  :: (Monad m, Functor f, Functor g) =>
        Stream (Sum f g) m r -> Stream g m (Stream (Sum f g) m r)
---  cleanR = fmap (maps switch) . cleanL . maps switch
-  cleanR = loop where
-    loop s = do
+  cleanR = go where
+    go s = do
      e <- lift $ inspect s
      case e of
       Left r           -> return (return r)
       Right (InL fstr) -> return (wrap (InL fstr))
-      Right (InR gstr) -> wrap (fmap loop gstr)
+      Right (InR gstr) -> wrap (fmap go gstr)
 {-#INLINABLE groups #-}
     
 -- groupInL :: (Monad m, Functor f, Functor g)
@@ -1036,7 +1220,7 @@
     So, for example, we might write
 
 >>> let justFour str = if length str == 4 then Just str else Nothing
->>> let four = untilJust (liftM justFour getLine)
+>>> let four = untilJust (fmap justFour getLine)
 >>> run four
 one<Enter>
 two<Enter>
@@ -1052,7 +1236,9 @@
 
 -}
 never :: (Monad m, Applicative f) => Stream f m r
-never =  let loop = Effect $ return $ Step $ pure loop in loop
+-- The Monad m constraint should really be an Applicative one,
+-- but we still support old versions of base.
+never =  let loop = Step $ pure (Effect (return loop)) in loop
 {-#INLINABLE never #-}
 
 
@@ -1074,7 +1260,7 @@
 --             then return s
 --             else case s of
 --               Return r -> Return (Return r)
---               Effect m -> Effect (liftM loop m)
+--               Effect m -> Effect (fmap loop m)
 --               Step f   -> Step (fmap loop f)
 --     loop str
 --   where
@@ -1099,7 +1285,7 @@
 --       then loop (addUTCTime cutoff utc) stream
 --       else case stream of
 --         Return r  -> Return r
---         Effect m  -> Effect $ liftM (loop final) m
+--         Effect m  -> Effect $ fmap (loop final) m
 --         Step fstr -> Step $ fmap (periods seconds) (cutoff_ final (Step fstr))
 --
 --         -- do
@@ -1109,7 +1295,7 @@
 --         --           then return s
 --         --           else case s of
 --         --             Return r -> Return (Return r)
---         --             Effect m -> Effect (liftM sloop m)
+--         --             Effect m -> Effect (fmap sloop m)
 --         --             Step f   -> Step (fmap sloop f)
 --         --   Step (Step (fmap (fmap (periods seconds) . sloop) fstr))
 --           -- str <- m
@@ -1131,7 +1317,7 @@
 --             then Return s
 --             else case s of
 --               Return r -> Return (Return r)
---               Effect m -> Effect (liftM loop m)
+--               Effect m -> Effect (fmap loop m)
 --               Step f   -> Step (fmap loop f)
 --     loop str
 
@@ -1150,7 +1336,7 @@
     
 cutoff :: (Monad m, Functor f) => Int -> Stream f m r -> Stream f m (Maybe r)
 cutoff = loop where
-  loop 0 str = return Nothing
+  loop 0 _ = return Nothing
   loop n str = do
       e <- lift $ inspect str
       case e of
diff --git a/src/Streaming/Prelude.hs b/src/Streaming/Prelude.hs
--- a/src/Streaming/Prelude.hs
+++ b/src/Streaming/Prelude.hs
@@ -47,9 +47,18 @@
 > --------------------------------------------------------------------------------------------------------------------
 >
 -}
-{-# LANGUAGE RankNTypes, BangPatterns, DeriveDataTypeable, TypeFamilies,
-             DeriveFoldable, DeriveFunctor, DeriveTraversable, CPP, Trustworthy #-}
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE DeriveFoldable #-}
+{-# LANGUAGE DeriveFunctor #-}
+{-# LANGUAGE DeriveTraversable #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeFamilies #-}
 
+{-# OPTIONS_GHC -Wall #-}
+
 module Streaming.Prelude (
     -- * Types
     Of (..)
@@ -61,7 +70,6 @@
     , stdinLn
     , readLn
     , fromHandle
-    , readFile
     , iterate
     , iterateM
     , repeat
@@ -72,7 +80,6 @@
     , replicateM
     , enumFrom
     , enumFromThen
-    , seconds
     , unfoldr
     
 
@@ -84,7 +91,6 @@
     , mapM_
     , print
     , toHandle
-    , writeFile
     , effects
     , erase
     , drained
@@ -95,7 +101,9 @@
     , map
     , mapM
     , maps
+    , mapsPost
     , mapped
+    , mappedPost
     , for
     , with
     , subst
@@ -106,6 +114,7 @@
     , sequence
     , filter
     , filterM
+    , mapMaybeM
     , delay
     , intersperse
     , take
@@ -231,12 +240,10 @@
 
     -- * Basic Type
     , Stream
-
   ) where
 import Streaming.Internal
 
 import Control.Monad hiding (filterM, mapM, mapM_, foldM, foldM_, replicateM, sequence)
-import Data.Data ( Data, Typeable )
 import Data.Functor.Identity
 import Data.Functor.Sum
 import Control.Monad.Trans
@@ -244,8 +251,6 @@
 import Data.Functor (Functor (..), (<$))
 
 import qualified Prelude as Prelude
-import Data.Foldable (Foldable)
-import Data.Traversable (Traversable)
 import qualified Data.Foldable as Foldable
 import qualified Data.Sequence as Seq
 import Text.Read (readMaybe)
@@ -254,7 +259,7 @@
                       , takeWhile, enumFrom, enumFromTo, enumFromThen, length
                       , print, zipWith, zip, zipWith3, zip3, unzip, seq, show, read
                       , readLn, sequence, concat, span, break, readFile, writeFile
-                      , minimum, maximum, elem, notElem, intersperse, all, any, head
+                      , minimum, maximum, elem, notElem, all, any, head
                       , last)
 
 import qualified GHC.IO.Exception as G
@@ -262,66 +267,9 @@
 import Foreign.C.Error (Errno(Errno), ePIPE)
 import Control.Exception (throwIO, try)
 import Data.Monoid (Monoid (mappend, mempty))
-import Data.String (IsString (..))
 import Control.Concurrent (threadDelay)
-import Data.Time (getCurrentTime, diffUTCTime, picosecondsToDiffTime)
-import Data.Functor.Classes
 import Data.Functor.Compose
-import Control.Monad.Trans.Resource
-
-import GHC.Magic
-#if MIN_VERSION_base(4,8,0)
-import Data.Bifunctor
-#endif
-
--- | A left-strict pair; the base functor for streams of individual elements.
-data Of a b = !a :> b
-    deriving (Data, Eq, Foldable, Ord,
-              Read, Show, Traversable, Typeable)
-infixr 5 :>
-
-instance (Monoid a, Monoid b) => Monoid (Of a b) where
-  mempty = mempty :> mempty
-  {-#INLINE mempty #-}
-  mappend (m :> w) (m' :> w') = mappend m m' :> mappend w w'
-  {-#INLINE mappend #-}
-
-instance Functor (Of a) where
-  fmap f (a :> x) = a :> f x
-  {-#INLINE fmap #-}
-  a <$ (b :> x)   = b :> a
-  {-#INLINE (<$) #-}
-
-#if MIN_VERSION_base(4,8,0)
-instance Bifunctor Of where
-  bimap f g (a :> b) = f a :> g b
-  {-#INLINE bimap #-}
-  first f   (a :> b) = f a :> b
-  {-#INLINE first #-}
-  second g  (a :> b) = a :> g b
-  {-#INLINE second #-}
-#endif
-
-instance Monoid a => Applicative (Of a) where
-  pure x = mempty :> x
-  {-#INLINE pure #-}
-  m :> f <*> m' :> x = mappend m m' :> f x
-  {-#INLINE (<*>) #-}
-  m :> x *> m' :> y  = mappend m m' :> y
-  {-#INLINE (*>) #-}
-  m :> x <* m' :> y  = mappend m m' :> x
-  {-#INLINE (<*) #-}
-
-instance Monoid a => Monad (Of a) where
-  return x = mempty :> x
-  {-#INLINE return #-}
-  m :> x >> m' :> y = mappend m m' :> y
-  {-#INLINE (>>) #-}
-  m :> x >>= f = let m' :> y = f x in mappend m m' :> y
-  {-#INLINE (>>=) #-}
-
-instance (r ~ (), Monad m, f ~ Of Char) => IsString (Stream f m r) where
-  fromString = each
+import Data.Functor.Of
 
 -- instance (Eq a) => Eq1 (Of a) where eq1 = (==)
 -- instance (Ord a) => Ord1 (Of a) where compare1 = compare
@@ -388,10 +336,10 @@
  -}
 
 fst' :: Of a b -> a
-fst' (a :> b) = a
+fst' (a :> _) = a
 {-#INLINE fst' #-}
 snd' :: Of a b -> b
-snd' (a :> b) = b
+snd' (_ :> b) = b
 {-#INLINE snd' #-}
 
 {-| Map a function over the first element of an @Of@ pair
@@ -441,7 +389,7 @@
 all_ :: Monad m => (a -> Bool) -> Stream (Of a) m r -> m Bool
 all_ thus = loop True where
   loop b str = case str of
-    Return r -> return b
+    Return _ -> return b
     Effect m -> m >>= loop b
     Step (a :> rest) -> if thus a
       then loop True rest
@@ -464,7 +412,7 @@
 any_ :: Monad m => (a -> Bool) -> Stream (Of a) m r -> m Bool
 any_ thus = loop False where
   loop b str = case str of
-    Return r -> return b
+    Return _ -> return b
     Effect m -> m >>= loop b
     Step (a :> rest) -> if thus a
       then return True
@@ -485,11 +433,11 @@
 
 break :: Monad m => (a -> Bool) -> Stream (Of a) m r
       -> Stream (Of a) m (Stream (Of a) m r)
-break pred = loop where
+break thePred = loop where
   loop str = case str of
     Return r         -> Return (Return r)
-    Effect m          -> Effect $ liftM loop m
-    Step (a :> rest) -> if (pred a)
+    Effect m          -> Effect $ fmap loop m
+    Step (a :> rest) -> if (thePred a)
       then Return (Step (a :> rest))
       else Step (a :> loop rest)
 {-# INLINABLE break #-}
@@ -514,18 +462,18 @@
 
 -}
 breakWhen :: Monad m => (x -> a -> x) -> x -> (x -> b) -> (b -> Bool) -> Stream (Of a) m r -> Stream (Of a) m (Stream (Of a) m r)
-breakWhen step begin done pred = loop0 begin
+breakWhen step begin done thePred = loop0 begin
   where
     loop0 x stream = case stream of
         Return r -> return (return r)
-        Effect mn  -> Effect $ liftM (loop0 x) mn
+        Effect mn  -> Effect $ fmap (loop0 x) mn
         Step (a :> rest) -> loop a (step x a) rest
     loop a !x stream = do
-      if pred (done x)
+      if thePred (done x)
         then return (yield a >> stream)
         else case stream of
           Return r -> yield a >> return (return r)
-          Effect mn  -> Effect $ liftM (loop a x) mn
+          Effect mn  -> Effect $ fmap (loop a x) mn
           Step (a' :> rest) -> do
             yield a
             loop a' (step x a') rest
@@ -571,7 +519,7 @@
 chain f = loop where
   loop str = case str of
     Return r -> return r
-    Effect mn  -> Effect (liftM loop mn)
+    Effect mn  -> Effect (fmap loop mn)
     Step (a :> rest) -> Effect $ do
       f a
       return (Step (a :> loop rest))
@@ -683,8 +631,8 @@
 > takeWhile' thus = S.drained . S.span thus
 
 -}
-drained :: (Monad m, Monad (t m), Functor (t m), MonadTrans t) => t m (Stream (Of a) m r) -> t m r
-drained = join . fmap (lift . effects)
+drained :: (Monad m, Monad (t m), MonadTrans t) => t m (Stream (Of a) m r) -> t m r
+drained tms = tms >>= lift . effects
 {-#INLINE drained #-}
 
 -- ---------------
@@ -714,10 +662,10 @@
 drop n str | n <= 0 = str
 drop n str = loop n str where
   loop 0 stream = stream
-  loop n stream = case stream of
+  loop m stream = case stream of
       Return r       -> Return r
-      Effect ma      -> Effect (liftM (loop n) ma)
-      Step (a :> as) -> loop (n-1) as
+      Effect ma      -> Effect (fmap (loop m) ma)
+      Step (_ :> as) -> loop (m-1) as
 {-# INLINABLE drop #-}
 
 -- ---------------
@@ -738,11 +686,11 @@
 
 -}
 dropWhile :: Monad m => (a -> Bool) -> Stream (Of a) m r -> Stream (Of a) m r
-dropWhile pred = loop where
+dropWhile thePred = loop where
   loop stream = case stream of
     Return r       -> Return r
-    Effect ma       -> Effect (liftM loop ma)
-    Step (a :> as) -> if pred a
+    Effect ma       -> Effect (fmap loop ma)
+    Step (a :> as) -> if thePred a
       then loop as
       else Step (a :> as)
 {-# INLINABLE dropWhile #-}
@@ -799,21 +747,21 @@
 
 elem :: (Monad m, Eq a) => a -> Stream (Of a) m r -> m (Of Bool r)
 elem a' = loop False where
-  loop True str = liftM (True :>) (effects str)
+  loop True str = fmap (True :>) (effects str)
   loop False str = case str of
     Return r -> return (False :> r)
     Effect m -> m >>= loop False
     Step (a:> rest) ->
       if a == a'
-        then liftM (True :>) (effects rest)
+        then fmap (True :>) (effects rest)
         else loop False rest
 {-#INLINABLE elem #-}
 
 elem_ :: (Monad m, Eq a) => a -> Stream (Of a) m r -> m Bool
 elem_ a' = loop False where
-  loop True str = return True
+  loop True _ = return True
   loop False str = case str of
-    Return r -> return False
+    Return _ -> return False
     Effect m -> m >>= loop False
     Step (a:> rest) ->
       if a == a'
@@ -875,8 +823,8 @@
 erase = loop where
   loop str = case str of
     Return r -> Return r
-    Effect m -> Effect (liftM loop m)
-    Step (a:>rest) -> Step (Identity (loop rest))
+    Effect m -> Effect (fmap loop m)
+    Step (_:>rest) -> Step (Identity (loop rest))
 {-# INLINABLE erase #-}
 
 -- ---------------
@@ -885,13 +833,13 @@
 
 -- | Skip elements of a stream that fail a predicate
 filter  :: (Monad m) => (a -> Bool) -> Stream (Of a) m r -> Stream (Of a) m r
-filter pred = loop where
+filter thePred = loop where
   loop str = case str of
     Return r       -> Return r
-    Effect m       -> Effect (liftM loop m)
-    Step (a :> as) -> if pred a
-                         then Step (a :> loop as)
-                         else loop as
+    Effect m       -> Effect (fmap loop m)
+    Step (a :> as) -> if thePred a
+      then Step (a :> loop as)
+      else loop as
 {-# INLINE filter #-}  -- ~ 10% faster than INLINABLE in simple bench
 
                          
@@ -901,12 +849,12 @@
 
 -- | Skip elements of a stream that fail a monadic test
 filterM  :: (Monad m) => (a -> m Bool) -> Stream (Of a) m r -> Stream (Of a) m r
-filterM pred = loop where
+filterM thePred = loop where
   loop str = case str of
     Return r       -> Return r
-    Effect m       -> Effect $ liftM loop m
+    Effect m       -> Effect $ fmap loop m
     Step (a :> as) -> Effect $ do
-      bool <- pred a
+      bool <- thePred a
       if bool
         then return $ Step (a :> loop as)
         else return $ loop as
@@ -985,7 +933,7 @@
 > Control.Foldl.purely fold :: Monad m => Fold a b -> Stream (Of a) m () -> m b
 -}
 fold_ :: Monad m => (x -> a -> x) -> x -> (x -> b) -> Stream (Of a) m r -> m b
-fold_ step begin done = liftM (\(a:>rest) -> a) . fold step begin done
+fold_ step begin done = fmap (\(a :> _) -> a) . fold step begin done
 {-#INLINE fold_ #-}
 
 {-| Strict fold of a 'Stream' of elements that preserves the return value.
@@ -1037,7 +985,7 @@
 foldM_
     :: Monad m
     => (x -> a -> m x) -> m x -> (x -> m b) -> Stream (Of a) m r -> m b
-foldM_ step begin done  = liftM (\(a :> rest) -> a) . foldM step begin done
+foldM_ step begin done = fmap (\(a :> _) -> a) . foldM step begin done
 {-#INLINE foldM_ #-}
 
 {-| Strict, monadic fold of the elements of a 'Stream (Of a)'
@@ -1123,10 +1071,8 @@
 for str0 act = loop str0 where
   loop str = case str of
     Return r         -> Return r
-    Effect m          -> Effect $ liftM loop m
-    Step (a :> rest) -> do
-      act a
-      loop rest
+    Effect m          -> Effect $ fmap loop m
+    Step (a :> rest) -> act a *> loop rest
 {-# INLINABLE for #-}
 
 -- -| Group layers of any functor by comparisons on a preliminary annotation
@@ -1145,11 +1091,11 @@
 --                 fmap loop (Step $ Compose (a :> fmap (span' (equals a)) p'))
 --   span' :: (Monad m, Functor f) => (a -> Bool) -> Stream (Compose (Of a) f) m r
 --         -> Stream (Compose (Of a) f) m (Stream (Compose (Of a) f) m r)
---   span' pred = loop where
+--   span' thePred = loop where
 --     loop str = case str of
 --       Return r         -> Return (Return r)
---       Effect m          -> Effect $ liftM loop m
---       Step s@(Compose (a :> rest)) -> case pred a  of
+--       Effect m          -> Effect $ fmap loop m
+--       Step s@(Compose (a :> rest)) -> case thePred a  of
 --         True  -> Step (Compose (a :> fmap loop rest))
 --         False -> Return (Step s)
 -- {-# INLINABLE groupedBy #-}
@@ -1204,20 +1150,20 @@
 
 head_ :: Monad m => Stream (Of a) m r -> m (Maybe a)
 head_ str = case str of
-  Return r            -> return Nothing
-  Effect m            -> m >>= head_
-  Step (a :> rest)    -> effects rest >> return (Just a)
+  Return _ -> return Nothing
+  Effect m -> m >>= head_
+  Step (a :> _) -> return (Just a)
 {-#INLINABLE head_ #-}
 
 intersperse :: Monad m => a -> Stream (Of a) m r -> Stream (Of a) m r
 intersperse x str = case str of
     Return r -> Return r
-    Effect m -> Effect (liftM (intersperse x) m)
+    Effect m -> Effect (fmap (intersperse x) m)
     Step (a :> rest) -> loop a rest
   where
-  loop !a str = case str of
+  loop !a theStr = case theStr of
     Return r -> Step (a :> Return r)
-    Effect m -> Effect (liftM (loop a) m)
+    Effect m -> Effect (fmap (loop a) m)
     Step (b :> rest) -> Step (a :> Step (x :> loop b rest))
 {-#INLINABLE intersperse #-}
 
@@ -1250,11 +1196,11 @@
 
 last :: Monad m => Stream (Of a) m r -> m (Of (Maybe a) r)
 last = loop Nothing_ where
-  loop m str = case str of
-    Return r            -> case m of
+  loop mb str = case str of
+    Return r            -> case mb of
       Nothing_ -> return (Nothing :> r)
       Just_ a  -> return (Just a :> r)
-    Effect m            -> m >>= last
+    Effect m            -> m >>= loop mb
     Step (a :> rest)  -> loop (Just_ a) rest
 {-#INLINABLE last #-}
 
@@ -1262,14 +1208,15 @@
 
 last_ :: Monad m => Stream (Of a) m r -> m (Maybe a)
 last_ = loop Nothing_ where
-  loop m str = case str of
-    Return r            -> case m of
+  loop mb str = case str of
+    Return _ -> case mb of
       Nothing_ -> return Nothing
       Just_ a  -> return (Just a)
-    Effect m            -> m >>= last_
-    Step (a :> rest)  -> loop (Just_ a) rest
+    Effect m -> m >>= loop mb
+    Step (a :> rest) -> loop (Just_ a) rest
 {-#INLINABLE last_ #-}
 
+
 -- ---------------
 -- length
 -- ---------------
@@ -1313,7 +1260,7 @@
 -- loop where  --
   -- loop stream = case stream of
   --   Return r -> Return r
-  --   Effect m -> Effect (liftM loop m)
+  --   Effect m -> Effect (fmap loop m)
   --   Step (a :> as) -> Step (f a :> loop as)
 {-# INLINABLE map #-}
 -- {-# NOINLINE [1] map #-}
@@ -1336,7 +1283,7 @@
 mapM f = loop where
   loop str = case str of
     Return r       -> Return r
-    Effect m        -> Effect (liftM loop m)
+    Effect m        -> Effect (fmap loop m)
     Step (a :> as) -> Effect $ do
       a' <- f a
       return (Step (a' :> loop as) )
@@ -1363,11 +1310,9 @@
 mapM_ :: Monad m => (a -> m b) -> Stream (Of a) m r -> m r
 mapM_ f = loop where
   loop str = case str of
-    Return r       -> return r
-    Effect m        -> m >>= loop
-    Step (a :> as) -> do
-      f a
-      loop as
+    Return r -> return r
+    Effect m -> m >>= loop
+    Step (a :> as) -> f a *> loop as
 {-# INLINABLE mapM_ #-}
 
 
@@ -1386,8 +1331,8 @@
 > mapped return        = id
 > maps f . maps g      = maps (f . g)
 > mapped f . mapped g  = mapped (f <=< g)
-> maps f . mapped g    = mapped (liftM f . g)
-> mapped f . maps g    = mapped (f <=< liftM g)
+> maps f . mapped g    = mapped (fmap f . g)
+> mapped f . maps g    = mapped (f <=< fmap g)
 
      @maps@ is more fundamental than @mapped@, which is best understood as a convenience
      for effecting this frequent composition:
@@ -1401,7 +1346,15 @@
 mapped = mapsM
 {-#INLINE mapped #-}
 
+{-| A version of 'mapped' that imposes a 'Functor' constraint on the target functor rather
+    than the source functor. This version should be preferred if 'fmap' on the target
+    functor is cheaper.
 
+-}
+mappedPost :: (Monad m, Functor g) => (forall x . f x -> m (g x)) -> Stream f m r -> Stream g m r
+mappedPost = mapsMPost
+{-# INLINE mappedPost #-}
+
 {-| Fold streamed items into their monoidal sum
 
 >>> S.mconcat $ S.take 2 $ S.map (Data.Monoid.Last . Just) (S.stdinLn)
@@ -1458,8 +1411,8 @@
 
      Similarly:
 
-> IOStreams.unfoldM (liftM (either (const Nothing) Just) . next) :: Stream (Of a) IO b -> IO (InputStream a)
-> Conduit.unfoldM (liftM (either (const Nothing) Just) . next)   :: Stream (Of a) m r -> Source a m r
+> IOStreams.unfoldM (fmap (either (const Nothing) Just) . next) :: Stream (Of a) IO b -> IO (InputStream a)
+> Conduit.unfoldM (fmap (either (const Nothing) Just) . next)   :: Stream (Of a) m r -> Source a m r
 
      But see 'uncons', which is better fitted to these @unfoldM@s
 -}
@@ -1478,21 +1431,21 @@
 
 notElem :: (Monad m, Eq a) => a -> Stream (Of a) m r -> m (Of Bool r)
 notElem a' = loop True where
-  loop False str = liftM (False :>) (effects str)
+  loop False str = fmap (False :>) (effects str)
   loop True str = case str of
     Return r -> return (True:> r)
     Effect m -> m >>= loop True
     Step (a:> rest) ->
       if a == a'
-        then liftM (False :>) (effects rest)
+        then fmap (False :>) (effects rest)
         else loop True rest
 {-#INLINABLE notElem #-}
 
 notElem_ :: (Monad m, Eq a) => a -> Stream (Of a) m r -> m Bool
 notElem_ a' = loop True where
-  loop False str = return False
+  loop False _ = return False
   loop True str = case str of
-    Return r -> return True
+    Return _ -> return True
     Effect m -> m >>= loop True
     Step (a:> rest) ->
       if a == a'
@@ -1509,7 +1462,7 @@
 partition thus = loop where
    loop str = case str of
      Return r -> Return r
-     Effect m -> Effect (liftM loop (lift m))
+     Effect m -> Effect (fmap loop (lift m))
      Step (a :> rest) -> if thus a
        then Step (a :> loop rest)
        else Effect $ do
@@ -1541,7 +1494,7 @@
 partitionEithers =  loop where
    loop str = case str of
      Return r -> Return r
-     Effect m -> Effect (liftM loop (lift m))
+     Effect m -> Effect (fmap loop (lift m))
      Step (Left a :> rest) -> Step (a :> loop rest)
      Step (Right b :> rest) -> Effect $ do
        yield b
@@ -1621,7 +1574,7 @@
 
 -- | Repeat an element several times.
 replicate :: Monad m => Int -> a -> Stream (Of a) m ()
-replicate n a | n <= 0 = return ()
+replicate n _ | n <= 0 = return ()
 replicate n a = loop n where
   loop 0 = Return ()
   loop m = Effect (return (Step (a :> loop (m-1))))
@@ -1635,12 +1588,12 @@
 
 -}
 replicateM :: Monad m => Int -> m a -> Stream (Of a) m ()
-replicateM n ma | n <= 0 = return ()
+replicateM n _ | n <= 0 = return ()
 replicateM n ma = loop n where
   loop 0 = Return ()
-  loop n = Effect $ do
+  loop m = Effect $ do
     a <- ma
-    return (Step (a :> loop (n-1)))
+    return (Step (a :> loop (m-1)))
 {-# INLINABLE replicateM #-}
 
 {-| Read an @IORef (Maybe a)@ or a similar device until it reads @Nothing@.
@@ -1684,7 +1637,7 @@
   loop !acc stream = do
     case stream of
       Return r -> Return r
-      Effect m -> Effect (liftM (loop acc) m)
+      Effect m -> Effect (fmap (loop acc) m)
       Step (a :> rest) -> 
         let !acc' = step acc a 
         in Step (done acc' :> loop acc' rest)
@@ -1745,7 +1698,7 @@
     loop !m !x stream = do
       case stream of
         Return r -> return r
-        Effect mn  -> Effect $ liftM (loop m x) mn
+        Effect mn  -> Effect $ fmap (loop m x) mn
         Step (a :> rest) -> do
           case m of
             Nothing' -> do
@@ -1783,22 +1736,6 @@
 
   -}
 
-seconds :: Stream (Of Double) IO r
-seconds = do
-    e <- lift $ next preseconds
-    case e of
-      Left r -> return r
-      Right (t, rest) -> do
-        yield 0
-        map (subtract t) rest
- where
-  preseconds :: Stream (Of Double) IO r
-  preseconds = do
-    utc <- liftIO getCurrentTime
-    map ((/1000000000) . nice utc) (repeatM getCurrentTime)
-   where
-     nice u u' = fromIntegral $ truncate (1000000000 * diffUTCTime u' u)
-
 -- ---------------
 -- sequence
 -- ---------------
@@ -1817,7 +1754,7 @@
 sequence = loop where
   loop stream = case stream of
     Return r          -> Return r
-    Effect m           -> Effect $ liftM loop m
+    Effect m           -> Effect $ fmap loop m
     Step (ma :> rest) -> Effect $ do
       a <- ma
       return (Step (a :> loop rest))
@@ -1870,11 +1807,11 @@
 -- | Stream elements until one fails the condition, return the rest.
 span :: Monad m => (a -> Bool) -> Stream (Of a) m r
       -> Stream (Of a) m (Stream (Of a) m r)
-span pred = loop where
+span thePred = loop where
   loop str = case str of
     Return r         -> Return (Return r)
-    Effect m          -> Effect $ liftM loop m
-    Step (a :> rest) -> if pred a
+    Effect m          -> Effect $ fmap loop m
+    Step (a :> rest) -> if thePred a
       then Step (a :> loop rest)
       else Return (Step (a :> rest))
 {-# INLINABLE span #-}
@@ -1894,7 +1831,7 @@
 split t  = loop  where
   loop stream = case stream of
     Return r -> Return r
-    Effect m -> Effect (liftM loop m)
+    Effect m -> Effect (fmap loop m)
     Step (a :> rest) ->
          if a /= t
             then Step (fmap loop (yield a >> break (== t) rest))
@@ -1902,9 +1839,9 @@
 {-#INLINABLE split #-}
 
 {-| Split a succession of layers after some number, returning a streaming or
---   effectful pair. This function is the same as the 'splitsAt' exported by the
---   @Streaming@ module, but since this module is imported qualified, it can
---   usurp a Prelude name. It specializes to:
+    effectful pair. This function is the same as the 'splitsAt' exported by the
+    @Streaming@ module, but since this module is imported qualified, it can
+    usurp a Prelude name. It specializes to:
 
 >  splitAt :: (Monad m, Functor f) => Int -> Stream (Of a) m r -> Stream (Of a) m (Stream (Of a) m r)
 
@@ -1929,7 +1866,7 @@
 subst f s = loop s where
   loop str = case str of
     Return r         -> Return r
-    Effect m         -> Effect (liftM loop m)
+    Effect m         -> Effect (fmap loop m)
     Step (a :> rest) -> Step (loop rest <$ f a)
 {-#INLINABLE subst #-}
 -- ---------------
@@ -1954,13 +1891,14 @@
 -}
 
 take :: (Monad m, Functor f) => Int -> Stream f m r -> Stream f m ()
-take n0 str | n0 <= 0 = return ()
+take n0 _ | n0 <= 0 = return ()
 take n0 str = loop n0 str where
-  loop 0 p = return ()
+  loop 0 _ = return ()
   loop n p =
-    case p of Step fas -> Step (fmap (loop (n-1)) fas)
-              Effect m -> Effect (liftM (loop n) m)
-              Return r -> Return ()
+    case p of
+      Step fas -> Step (fmap (loop (n-1)) fas)
+      Effect m -> Effect (fmap (loop n) m)
+      Return _ -> Return ()
 {-# INLINABLE take #-}
 
 -- ---------------
@@ -1983,22 +1921,22 @@
 
 -}
 takeWhile :: Monad m => (a -> Bool) -> Stream (Of a) m r -> Stream (Of a) m ()
-takeWhile pred = loop where
+takeWhile thePred = loop where
   loop str = case str of
-    Step (a :> as) -> when (pred a) (Step (a :> loop as))
-    Effect m              -> Effect (liftM loop m)
-    Return r              -> Return ()
+    Step (a :> as) -> when (thePred a) (Step (a :> loop as))
+    Effect m -> Effect (fmap loop m)
+    Return _ -> Return ()
 {-# INLINE takeWhile #-}
 
 {-| Like 'takeWhile', but takes a monadic predicate. -}
 takeWhileM :: Monad m => (a -> m Bool) -> Stream (Of a) m r -> Stream (Of a) m ()
-takeWhileM pred = loop where
+takeWhileM thePred = loop where
   loop str = case str of
     Step (a :> as) -> do
-      b <- lift (pred a)
+      b <- lift (thePred a)
       when b (Step (a :> loop as))
-    Effect m -> Effect (liftM loop m)
-    Return r -> Return ()
+    Effect m -> Effect (fmap loop m)
+    Return _ -> Return ()
 {-# INLINE takeWhileM #-}
 
 
@@ -2046,10 +1984,10 @@
 > Conduit.unfoldM uncons   :: Stream (Of a) m r -> Conduit.Source m a
 
 -}
-uncons :: Monad m => Stream (Of a) m () -> m (Maybe (a, Stream (Of a) m ()))
+uncons :: Monad m => Stream (Of a) m r -> m (Maybe (a, Stream (Of a) m r))
 uncons = loop where
   loop stream = case stream of
-    Return ()        -> return Nothing
+    Return _         -> return Nothing
     Effect m          -> m >>= loop
     Step (a :> rest) -> return (Just (a,rest))
 {-# INLINABLE uncons #-}
@@ -2127,7 +2065,7 @@
 with s f = loop s where
   loop str = case str of
     Return r         -> Return r
-    Effect m         -> Effect (liftM loop m)
+    Effect m         -> Effect (fmap loop m)
     Step (a :> rest) -> Step (loop rest <$ f a)
 {-#INLINABLE with #-}
 
@@ -2177,10 +2115,10 @@
   where
     loop str0 str1 = case str0 of
       Return r          -> Return r
-      Effect m           -> Effect $ liftM (\str -> loop str str1) m
+      Effect m           -> Effect $ fmap (\str -> loop str str1) m
       Step (a :> rest0) -> case str1 of
         Return r          -> Return r
-        Effect m           -> Effect $ liftM (loop str0) m
+        Effect m           -> Effect $ fmap (loop str0) m
         Step (b :> rest1) -> Step (f a b :>loop rest0 rest1)
 {-# INLINABLE zipWith #-}
 
@@ -2264,11 +2202,14 @@
 -}
 
 readLn :: (MonadIO m, Read a) => Stream (Of a) m ()
-readLn = do
-  str <- liftIO getLine
-  case readMaybe str of
-    Nothing -> readLn
-    Just n  -> yield n >> readLn
+readLn = loop where 
+  loop = do
+    eof <- liftIO IO.isEOF
+    unless eof $ do
+      str <- liftIO getLine
+      case readMaybe str of
+        Nothing -> readLn
+        Just n  -> yield n >> loop
 {-# INLINABLE readLn #-}
 
 
@@ -2374,44 +2315,7 @@
 stdoutLn' :: MonadIO m => Stream (Of String) m r -> m r
 stdoutLn' = toHandle IO.stdout
 
-{-| Read the lines of a file as Haskell 'String's
 
->>> runResourceT $ S.writeFile "lines.txt" $ S.take 2 S.stdinLn
-hello<Enter>
-world<Enter>
->>> runResourceT $ S.print $ S.readFile "lines.txt"
-"hello"
-"world"
-
-    'runResourceT', as it is used here, means something like 'closing_all_handles'.
-    It makes it possible to write convenient, fairly sensible versions of
-    'readFile', 'writeFile' and 'appendFile'. @IO.withFile IO.ReadMode ...@
-    is more complicated but is generally to be preferred. Its use is explained
-    <https://www.fpcomplete.com/user/snoyberg/library-documentation/resourcet here>.
-
--}
-
-readFile :: MonadResource m => FilePath -> Stream (Of String) m ()
-readFile f = bracketStream (IO.openFile f IO.ReadMode) (IO.hClose) fromHandle
-
-{-| Write a series of strings as lines to a file. The handle is
-    managed with 'ResourceT' (see the remarks on 'readFile'):
-
->>> runResourceT $ S.writeFile "lines.txt" $ S.take 2 S.stdinLn
-hello<Enter>
-world<Enter>
->>> runResourceT $ S.stdoutLn $ S.readFile "lines.txt"
-hello
-world
-
--}
-writeFile :: MonadResource m => FilePath -> Stream (Of String) m r -> m r
-writeFile f str = do
-  (key, handle) <- allocate (IO.openFile f IO.WriteMode) (IO.hClose)
-  r <- toHandle handle str
-  release key
-  return r
-
 -- -- * Producers
 -- -- $producers
 --   stdinLn  --
@@ -2662,6 +2566,18 @@
 >>>  (S.toList . mapped S.toList . chunksOf 4) $ (S.toList . mapped S.toList . chunksOf 3) $ S.copy $ (S.toList . mapped S.toList . chunksOf 2) $ S.copy $ each [1..12]
 [[1,2,3,4],[5,6,7,8],[9,10,11,12]] :> ([[1,2,3],[4,5,6],[7,8,9],[10,11,12]] :> ([[1,2],[3,4],[5,6],[7,8],[9,10],[11,12]] :> ()))
 
+
+@copy@ can be considered a special case of 'expand':
+
+@
+  copy = 'expand' $ \p (a :> as) -> a :> p (a :> as)
+@
+
+If 'Of' were an instance of 'Control.Comonad.Comonad', then one could write
+
+@
+  copy = 'expand' extend
+@
 -}
 copy
   :: Monad m =>
@@ -2669,7 +2585,7 @@
 copy = Effect . return . loop where
   loop str = case str of
     Return r         -> Return r
-    Effect m         -> Effect (liftM loop (lift m))
+    Effect m         -> Effect (fmap loop (lift m))
     Step (a :> rest) -> Effect (Step (a :> Return (Step (a :> loop rest))))
 {-#INLINABLE copy#-}
 
@@ -2725,12 +2641,18 @@
 >>> S.toList $ S.toList $ S.unzip (S.each xs)
 ["1","2","3","4","5"] :> ([1,2,3,4,5] :> ())
 
+'unzip' can be considered a special case of either 'unzips' or 'expand':
+
+@
+  unzip = 'unzips' . 'maps' (\((a,b) :> x) -> Compose (a :> b :> x))
+  unzip = 'expand' $ \p ((a,b) :> abs) -> b :> p (a :> abs)
+@
 -}
 unzip :: Monad m =>  Stream (Of (a,b)) m r -> Stream (Of a) (Stream (Of b) m) r
 unzip = loop where
  loop str = case str of
    Return r -> Return r
-   Effect m -> Effect (liftM loop (lift m))
+   Effect m -> Effect (fmap loop (lift m))
    Step ((a,b):> rest) -> Step (a :> Effect (Step (b :> Return (loop rest))))
 {-#INLINABLE unzip #-}
 
@@ -2749,7 +2671,7 @@
 catMaybes = loop where
   loop stream = case stream of
     Return r -> Return r
-    Effect m -> Effect (liftM loop m)
+    Effect m -> Effect (fmap loop m)
     Step (ma :> snext) -> case ma of
       Nothing -> loop snext
       Just a -> Step (a :> loop snext)
@@ -2764,7 +2686,7 @@
 mapMaybe phi = loop where
   loop stream = case stream of
     Return r -> Return r
-    Effect m -> Effect (liftM loop m)
+    Effect m -> Effect (fmap loop m)
     Step (a :> snext) -> case phi a of
       Nothing -> loop snext
       Just b -> Step (b :> loop snext)
@@ -2798,9 +2720,22 @@
     setup 0 !sequ str = do
        yield sequ 
        window (Seq.drop 1 sequ) str 
-    setup n sequ str = do 
+    setup m sequ str = do 
       e <- lift $ next str 
       case e of 
         Left r ->  yield sequ >> return r
-        Right (x,rest) -> setup (n-1) (sequ Seq.|> x) rest
+        Right (x,rest) -> setup (m-1) (sequ Seq.|> x) rest
 {-#INLINABLE slidingWindow #-}
+
+-- | Map monadically over a stream, producing a new stream
+--   only containing the 'Just' values.
+mapMaybeM :: Monad m => (a -> m (Maybe b)) -> Stream (Of a) m r -> Stream (Of b) m r
+mapMaybeM phi = loop where
+  loop stream = case stream of
+    Return r -> Return r
+    Effect m -> Effect (fmap loop m)
+    Step (a :> snext) -> Effect $ do
+      flip fmap (phi a) $ \x -> case x of
+        Nothing -> loop snext
+        Just b -> Step (b :> loop snext)
+{-#INLINABLE mapMaybeM #-}
diff --git a/streaming.cabal b/streaming.cabal
--- a/streaming.cabal
+++ b/streaming.cabal
@@ -1,5 +1,5 @@
 name:                streaming
-version:             0.1.4.5
+version:             0.2.0.0
 cabal-version:       >=1.10
 build-type:          Simple
 synopsis:            an elementary streaming prelude and general stream type.
@@ -186,45 +186,41 @@
 license:             BSD3
 license-file:        LICENSE
 author:              michaelt
-maintainer:          what_is_it_to_do_anything@yahoo.com
+maintainer:          andrew.thaddeus@gmail.com, what_is_it_to_do_anything@yahoo.com
 stability:           Experimental
-homepage:            https://github.com/michaelt/streaming
-bug-reports:         https://github.com/michaelt/streaming/issues
+homepage:            https://github.com/haskell-streaming/streaming
+bug-reports:         https://github.com/haskell-streaming/streaming/issues
 category:            Data, Pipes, Streaming
 extra-source-files:  README.md
 
 source-repository head
     type: git
-    location: https://github.com/michaelt/streaming
-
+    location: https://github.com/haskell-streaming/streaming
 
 library
-  exposed-modules:     Streaming,
-                       Streaming.Prelude,
-                       Streaming.Internal
-
-    -- other-modules:
-  other-extensions:    RankNTypes, CPP,
-                       StandaloneDeriving, FlexibleContexts,
-                       DeriveDataTypeable, DeriveFoldable,
-                       DeriveFunctor, DeriveTraversable,
-                       UndecidableInstances
-
-  build-depends:       base >=4.6 && <5
-                     , mtl >=2.1 && <2.3
-                     , mmorph >=1.0 && <1.1
-                     , transformers >=0.4 && <0.6
-                     , transformers-base < 0.5
-                     , resourcet > 1.1.0 && < 1.2
-                     , exceptions > 0.5 && < 0.9
-                     , monad-control >=0.3.1 && <1.1
-                     , time
-                     , ghc-prim
-                     , containers
-
+  exposed-modules:
+      Streaming
+    , Streaming.Prelude
+    , Streaming.Internal
+    , Data.Functor.Of
+  other-extensions:
+      RankNTypes
+    , CPP
+    , StandaloneDeriving
+    , FlexibleContexts
+    , DeriveDataTypeable
+    , DeriveFoldable
+    , DeriveFunctor
+    , DeriveTraversable
+    , UndecidableInstances
+  build-depends:
+      base >=4.8 && <5
+    , mtl >=2.1 && <2.3
+    , mmorph >=1.0 && <1.2
+    , transformers >=0.5 && <0.6
+    , transformers-base < 0.5
+    , exceptions > 0.5 && < 0.9
+    , ghc-prim
+    , containers
   hs-source-dirs:    src
   default-language:  Haskell2010
-
-
-
-
