diff --git a/quiver.cabal b/quiver.cabal
--- a/quiver.cabal
+++ b/quiver.cabal
@@ -1,5 +1,5 @@
 name:           quiver
-version:        0.0.0.6
+version:        0.0.0.7
 synopsis:       Quiver finite stream processing library
 homepage:       https://github.com/zadarnowski/quiver
 category:       Control
@@ -35,7 +35,7 @@
 source-repository this
   type:         git
   location:     https://github.com/zadarnowski/quiver.git
-  tag:          0.0.0.6
+  tag:          0.0.0.7
 
 library
   hs-source-dirs:   src
@@ -45,6 +45,7 @@
   exposed-modules:
     Control.Quiver
     Control.Quiver.Internal
+    Control.Quiver.SP
 
   build-depends:
     base >= 4.8 && < 5
diff --git a/src/Control/Quiver.lhs b/src/Control/Quiver.lhs
--- a/src/Control/Quiver.lhs
+++ b/src/Control/Quiver.lhs
@@ -13,66 +13,56 @@
 
 > module Control.Quiver (
 >   -- Imported from @Control.Quiver.Internal@:
->   P, SP, Consumer, Producer, Effect,
+>   P, Consumer, Producer, Effect,
 >   consume, produce, enclose, deliver,
 >   decouple, deplete,
 >   -- Defined below:
->   fetch, fetch',
->   emit, emit', emit_,
+>   fetch, fetch_,
+>   emit, emit_,
 >   qlift,
->   qpure, qpure_, qid,
->   qconcat, qconcat_,
+>   qpure, qid, qconcat,
 >   runEffect,
->   (>>->), (>->>),
+>   (>>->), (>->>), (>&>),
+>   qcompose,
 > ) where
 
 > import Control.Quiver.Internal
 
-> infixl 0 >>->, >->>
+> infixl 0 >>->, >->>, >&>
 
 > -- | @fetch x@ represents a singleton stream processor that
 > --   sends the request value @x@ upstream and delivers the
 > --   next input value received, or @Nothing@ if the upstream
 > --   processor has been depleted.
 
-> fetch :: a' -> P a' a b b' f (Maybe a)
+> fetch :: Functor f => a -> P a a' b b' f (Maybe a')
 > fetch x = consume x (deliver . Just) (deliver Nothing)
 
-> -- | @fetch' x q@ represents a singleton stream processor that
-> --   sends the request value @x@ upstream and delivers the next
-> --   input value received, or, if the upstream processor has
-> --   been depleted, continues with the decoupled processor @q@.
+> -- | @fetch_ x@ represents a singleton stream processor that
+> --   sends the request value @x@ upstream, discarding any
+> --   input received, for symmetry with @emit_@.
 
-> fetch' :: a' -> Producer b b' f a -> P a' a b b' f a
-> fetch' x q = consume x deliver q
+> fetch_ :: a -> P a a' b b' f ()
+> fetch_ x = consume x (deliver . const ()) (deliver ())
 
 > -- | @emit y@ represents a singleton stream processor that
 > --   produces a single output value @y@ and delivers the
 > --   response received from the downstream processor, or
 > --   @Nothing@ if the downstream processor has been decoupled.
 
-> emit :: b -> P a' a b b' f (Maybe b')
+> emit :: b -> P a a' b b' f (Maybe b')
 > emit y = produce y (deliver . Just) (deliver Nothing)
 
-> -- | @emit' y q@ represents a singleton stream processor that
-> --   produces a single output value @y@ and delivers the
-> --   response received from the downstream processor, or,
-> --   if the downstream processor has been decoupled, continues
-> --   with the depleted processor @q@.
-
-> emit' :: b -> Consumer a' a f b' -> P a' a b b' f b'
-> emit' y q = produce y deliver q
-
-> -- | @emit' y q@ represents a singleton stream processor that
+> -- | @emit_ y@ represents a singleton stream processor that
 > --   produces a single output value @y@, ignoring any response
 > --   received from the downstream processor.
 
-> emit_ :: b -> P a' a b b' f ()
+> emit_ :: b -> P a a' b b' f ()
 > emit_ y = produce y (deliver . const ()) (deliver ())
 
 > -- | @qlift@ lifts the value of a base functor into a stream processor.
 
-> qlift :: Functor f => f r -> P a' a b b' f r
+> qlift :: Functor f => f r -> P a a' b b' f r
 > qlift = enclose . fmap deliver
 
 > -- | @qpure g f z@ produces an infinite consumer/producer that
@@ -81,21 +71,11 @@
 > --   into an upstream request; the initial request is obtained
 > --   by applying @g@ to the initial response value @z@.
 
-> qpure :: (b' -> a') -> (a -> b) -> b' -> P a' a b b' f ()
+> qpure :: (b' -> a) -> (a' -> b) -> b' -> P a a' b b' f (Either a b)
 > qpure g f = cloop
 >  where
->   cloop y = let y' = g y in consume y' ploop (deliver ())
->   ploop x = let x' = f x in produce x' cloop (deliver ())
-
-> -- | @qpure_ f@ produces an infinite consumer/producer that
-> --   uses a pure function @f@ to convert every input value into
-> --   an output; equivalent to @qpure id f (const ())@.
-
-> qpure_ :: (a -> b) -> SP a b f ()
-> qpure_ f = cloop
->  where
->   cloop = consume () ploop (deliver ())
->   ploop x = produce (f x) (const cloop) (deliver ())
+>   cloop y = let y' = g y in consume y' ploop (deliver (Left y'))
+>   ploop x = let x' = f x in produce x' cloop (deliver (Right x'))
 
 > -- | A pull-based identity processor, equivalent to 'qpure id id'.
 
@@ -116,15 +96,6 @@
 >   ploop ys (x:xs) = produce x (\y -> ploop (y:ys) xs) (deliver (xs, reverse ys))
 >   ploop ys [] = cloop (reverse ys)
 
-> -- | A pull-based list flattening processor without requests.
-
-> qconcat_ :: SP [a] a f [a]
-> qconcat_ = cloop
->  where
->   cloop = consume () ploop (deliver [])
->   ploop (x:xs) = produce x (const $ ploop xs) (deliver xs)
->   ploop [] = cloop
-
 > -- | Evaluates an /effect/, i.e., a processor that is both detached
 > --   and depleted and hence neither consumes nor produces any input,
 > --   returning its delivered value. The base functor must be a monad.
@@ -144,7 +115,7 @@
 > --   represents a non-commutative monad, any effects of @p2@ will be
 > --   observed before those of @p1@.
 
-> (>>->) :: Functor f => P a' a b b' f r1 -> P b' b c c' f r2 -> P a' a c c' f (r1, r2)
+> (>>->) :: Functor f => P a a' b b' f r1 -> P b' b c c' f r2 -> P a a' c c' f (r1, r2)
 > (Consume x1 k1 q1) >>-> p2 = consume x1 ((>>-> p2) . k1) (q1 >>-> p2)
 > (Produce y1 k1 q1) >>-> p2 = loop p2
 >  where
@@ -166,7 +137,7 @@
 > --   represents a non-commutative monad, any effects of @p1@ will be
 > --   observed before those of @p2@.
 
-> (>->>) :: Functor f => P a' a b b' f r1 -> P b' b c c' f r2 -> P a' a c c' f (r1, r2)
+> (>->>) :: Functor f => P a a' b b' f r1 -> P b' b c c' f r2 -> P a a' c c' f (r1, r2)
 > p1 >->> (Consume x2 k2 q2) = loop p1
 >  where
 >   loop  (Consume x1 k1 q1) = consume x1 (loop . k1) (loop' q1)
@@ -180,3 +151,32 @@
 > p1 >->> (Produce y2 k2 q2) = produce y2 ((p1 >->>) . k2) (p1 >->> q2)
 > p1 >->> (Enclose f2)       = enclose (fmap (p1 >->>) f2)
 > p1 >->> (Deliver r2)       = fmap (, r2) (deplete p1)
+
+> -- | An infix version of @flip fmap@ with the same precedence and associativity
+> --   as the stream processor composition operators '>->>' and '>>->', indended
+> --   for idiomatic processing of composition deliverables using expressions
+> --   such as @p >->> q >&> fst@.
+
+> (>&>) :: Functor f => P a a' b b' f r -> (r -> r') -> P a a' b b' f r'
+> (>&>) = flip fmap
+
+> -- | The @qcompose f p q@ is precisely equivalent to @p >->> q >&> uncurry f@,
+> --   but faster. A rewrite rule is included to replace applications of
+> --   '>->>' followed by '>&>' into 'qcompose'.
+
+> qcompose :: Functor f => (r1 -> r2 -> r) -> P a a' b b' f r1 -> P b' b c c' f r2 -> P a a' c c' f r
+> qcompose ff p1 (Consume x2 k2 q2) = loop p1
+>  where
+>   loop  (Consume x1 k1 q1) = consume x1 (loop . k1) (loop' q1)
+>   loop  (Produce y1 k1  _) = qcompose ff (k1 x2) (k2 y1)
+>   loop  (Enclose f1)       = enclose (fmap loop f1)
+>   loop  (Deliver r1)       = fmap (ff r1) q2
+>   loop' (Consume  _  _ q1) = loop' q1
+>   loop' (Produce y1 k1  _) = qcompose ff (k1 x2) (k2 y1)
+>   loop' (Enclose f1)       = enclose (fmap loop' f1)
+>   loop' (Deliver r1)       = fmap (ff r1) q2
+> qcompose ff p1 (Produce y2 k2 q2) = produce y2 ((qcompose ff p1) . k2) (qcompose ff p1 q2)
+> qcompose ff p1 (Enclose f2)       = enclose (fmap (qcompose ff p1) f2)
+> qcompose ff p1 (Deliver r2)       = fmap (flip ff r2) (deplete p1)
+
+> {-# RULES "qcompose/fmap" forall p q f . fmap f (p >->> q) = qcompose (curry f) p q #-}
diff --git a/src/Control/Quiver/Internal.lhs b/src/Control/Quiver/Internal.lhs
--- a/src/Control/Quiver/Internal.lhs
+++ b/src/Control/Quiver/Internal.lhs
@@ -28,7 +28,7 @@
 > {-# LANGUAGE RankNTypes, TupleSections #-}
 
 > module Control.Quiver.Internal (
->   P (..), SP, Producer, Consumer, Effect,
+>   P (..), Producer, Consumer, Effect,
 >   consume, produce, enclose, deliver,
 >   decouple, deplete,
 > ) where
@@ -37,24 +37,24 @@
   Data Types
   ==========
 
-> -- | The main Quiver /stream processor/ type @P a' a b b' f r@,
+> -- | The main Quiver /stream processor/ type @P a a' b b' f r@,
 > --   representing a producer/consumer structure with /bidirectional/,
 > --   /bounded/ communication on both the upstream (consumer) and
 > --   downstream (producer) channel. The six type parameters have
 > --   the following intuitive meaning:
 > --
-> --   * @a'@ is the type of a /request/ values sent by the stream
+> --   * @a@ is the type of a /request/ values sent by the stream
 > --     processor to its upstream partner in order to receive the
 > --     next element of the input stream.
 > --
-> --   * @a@ is the type of the actual information being consumed
+> --   * @a'@ is the type of the actual information being consumed
 > --     by this stream processor (i.e., elements of its input stream.)
 > --
 > --   * @b@ is the type of the actual information being produced
 > --     by this stream processor (i.e., elements of its output stream.)
 > --
 > --   * @b'@ is the type of the /response/ values received from
-> --     the downstream partner for each elemnet of the output
+> --     the downstream partner for each element of the output
 > --     stream produced by this stream processor.
 > --
 > --   * @f@ is the type of the stream processor's /base functor/;
@@ -72,7 +72,7 @@
 > --   only time will tell whether this generalisation has useful
 > --   applications in the real world.
 
-> data P a' a b b' f r =
+> data P a a' b b' f r =
 
 >   -- | @Consume x k q@ represents a /consumer step/, in which
 >   --   the request @x@ is sent upstream and the returned input
@@ -81,7 +81,7 @@
 >   --   delivered its ultimate result, hence reaching the end
 >   --   of processing), to the /decoupled continuation/ @q@.
 
->   Consume a' (a -> P a' a b b' f r) (Producer b b' f r) |
+>   Consume a (a' -> P a a' b b' f r) (Producer b b' f r) |
 
 >   -- | @Produce y k q@ represent a /producer step/, in which
 >   --   the output value @y@ is sent downstream, and the returned
@@ -90,56 +90,55 @@
 >   --   (i.e., delivered its ultimate result, hence reaching the end
 >   --   of processing), to the /depleted continuation/ @q@.
 
->   Produce b  (b' -> P a' a b b' f r) (Consumer a' a f r) |
+>   Produce b  (b' -> P a a' b b' f r) (Consumer a a' f r) |
 
 >   -- | @Enclose@ allows for selective application of the base
 >   --   functor @f@ the the remainder of the computation.
 
->   Enclose (f (P a' a b b' f r)) |
+>   Enclose (f (P a a' b b' f r)) |
 
 >   -- | @Deliver r@ completes processing of information, delivering
 >   --   its ultimate result @r@.
 
 >   Deliver r
 
-> -- | A /simple processor/ with a unit request type and an unspecified
-> --   response type:
-
-> type SP a b f r = forall b' . P () a b b' f r
-
 > -- | A Quiver /producer/, represented by a stream processor
 > --   with unspecified input types.
 
-> type Producer b b' f r = forall a' a . P a' a b b' f r
+> type Producer b b' f r = forall a a' . P a a' b b' f r
 
 > -- | A Quiver /consumer/, represented by a stream processor
 > --   with unspecified output types.
 
-> type Consumer a' a f r = forall b b' . P a' a b b' f r
+> type Consumer a a' f r = forall b b' . P a a' b b' f r
 
 > -- | A Quiver /effect/, represented by a stream processor
 > --   with unspecified input and output types.
 
-> type Effect f r = forall a' a b b' . P a' a b b' f r
+> type Effect f r = forall a a' b b' . P a a' b b' f r
 
 
   Instances
   =========
 
-> instance Functor f => Functor (P a' a b b' f) where
+> instance Functor f => Functor (P a a' b b' f) where
 >   fmap ff (Consume x k q) = Consume x (fmap ff . k) (fmap ff q)
 >   fmap ff (Produce y k q) = Produce y (fmap ff . k) (fmap ff q)
 >   fmap ff (Enclose f)     = Enclose (fmap (fmap ff) f)
 >   fmap ff (Deliver r)     = Deliver (ff r)
+>   r <$ (Consume x k q) = Consume x ((r <$) . k) (r <$ q)
+>   r <$ (Produce y k q) = Produce y ((r <$) . k) (r <$ q)
+>   r <$ (Enclose f)     = Enclose (fmap (r <$) f)
+>   r <$ (Deliver _)     = Deliver r
 
-> instance Applicative f => Applicative (P a' a b b' f) where
+> instance Applicative f => Applicative (P a a' b b' f) where
 >   pure = Deliver
 >   (Consume x k q) <*> p = Consume x ((<*> p) . k) (q <*> decouple p)
 >   (Produce y k q) <*> p = Produce y ((<*> p) . k) (q <*> deplete p)
 >   (Enclose f)     <*> p = Enclose (fmap (<*> p) f)
 >   (Deliver r)     <*> p = fmap r p
 
-> instance Monad f => Monad (P a' a b b' f) where
+> instance Monad f => Monad (P a a' b b' f) where
 >   (Consume x k q) >>= kk = Consume x ((>>= kk) . k) (q >>= decouple . kk)
 >   (Produce y k q) >>= kk = Produce y ((>>= kk) . k) (q >>= deplete . kk)
 >   (Enclose f)     >>= kk = Enclose (fmap (>>= kk) f)
@@ -156,7 +155,7 @@
 > --   delivered its ultimate result, hence reaching the end
 > --   of processing), to the /decoupled continuation/ @q@.
 
-> consume :: a' -> (a -> P a' a b b' f r) -> Producer b b' f r -> P a' a b b' f r
+> consume :: a -> (a' -> P a a' b b' f r) -> Producer b b' f r -> P a a' b b' f r
 > consume = Consume
 
 > -- | @produce y k q@ represent a /producer step/, in which
@@ -166,19 +165,19 @@
 > --   (i.e., delivered its ultimate result, hence reaching the end
 > --   of processing), to the /depleted continuation/ @q@.
 
-> produce :: b  -> (b' -> P a' a b b' f r) -> Consumer a' a f r -> P a' a b b' f r
+> produce :: b -> (b' -> P a a' b b' f r) -> Consumer a a' f r -> P a a' b b' f r
 > produce = Produce
 
 > -- | @enclose@ allows for selective application of the base
 > --   functor @f@ the the remainder of the computation.
 
-> enclose :: f (P a' a b b' f r) -> P a' a b b' f r
+> enclose :: f (P a a' b b' f r) -> P a a' b b' f r
 > enclose = Enclose
 
 > -- | @deliver r@ completes processing of information, delivering
 > --   its ultimate result @r@.
 
-> deliver :: r -> P a' a b b' f r
+> deliver :: r -> P a a' b b' f r
 > deliver = Deliver
 
 
@@ -190,7 +189,7 @@
 > --   effectively converting @p@ into a producer processor that no longer
 > --   expects to receive any input.
 
-> decouple :: Functor f => P a' a b b' f r -> Producer b b' f r
+> decouple :: Functor f => P a a' b b' f r -> Producer b b' f r
 > decouple (Consume _ _ q) = q
 > decouple (Produce y k q) = Produce y (decouple . k) (decouple q)
 > decouple (Enclose f) = Enclose (fmap decouple f)
@@ -201,7 +200,7 @@
 > --   effectively converting @p@ into a consumer processor that will never
 > --   produce any more output.
 
-> deplete :: Functor f => P a' a b b' f r -> Consumer a' a f r
+> deplete :: Functor f => P a a' b b' f r -> Consumer a a' f r
 > deplete (Consume x k q) = Consume x (deplete . k) (deplete q)
 > deplete (Produce _ _ q) = q
 > deplete (Enclose f) = Enclose (fmap deplete f)
diff --git a/src/Control/Quiver/SP.lhs b/src/Control/Quiver/SP.lhs
new file mode 100644
--- /dev/null
+++ b/src/Control/Quiver/SP.lhs
@@ -0,0 +1,105 @@
+> -- | Module:    Control.Quiver.SP
+> -- Description: Simple stream processors
+> -- Copyright:   © 2015 Patryk Zadarnowski <pat@jantar.org>
+> -- License:     BSD3
+> -- Maintainer:  pat@jantar.org
+> -- Stability:   experimental
+> -- Portability: portable
+> --
+> -- This module provides a definition of a /simple processor/
+> -- with a unit request type and an unspecified acknowledgement
+> -- type, together with a number of common combinators for their
+> -- definitions.
+
+> {-# LANGUAGE PatternSynonyms, RankNTypes, ScopedTypeVariables, TupleSections #-}
+
+> module Control.Quiver.SP (
+>   SP,
+>   SPResult,
+>   pattern SPIncomplete,
+>   pattern SPComplete,
+>   pattern SPFailed,
+>   spfetch,
+>   sppure, spid, spconcat,
+>   spfold, spfoldl, spfoldr,
+> ) where
+
+> import Control.Quiver
+
+> -- | A /simple processor/ with a unit request type and an unspecified
+> --   response type:
+
+> type SP a b f r = forall b' . P () a b b' f r
+
+> -- | Simple processor result type.
+
+> type SPResult e = Maybe (Maybe e)
+
+> -- | Simple processor result value indicating premature termination of the consumer.
+
+> pattern SPIncomplete = Nothing
+
+> -- | Simple processor result value indicating successful processing of the entire input stream.
+
+> pattern SPComplete = Just Nothing
+
+> -- | Simple processor result value indicating unsuccessful processing of the input stream.
+
+> pattern SPFailed e = Just (Just e)
+
+> -- | @spfetch@ represents a singleton simple stream processor that
+> --   sends the request value @x@ upstream and delivers the
+> --   next input value received, or @Nothing@ if the upstream
+> --   processor has been depleted.
+
+> spfetch :: Functor f => SP a b f (Maybe a)
+> spfetch = fetch ()
+
+> -- | @sppure f@ produces an infinite consumer/producer that
+> --   uses a pure function @f@ to convert every input value into
+> --   an output; equivalent to @qpure id f (const ())@.
+
+> sppure :: (a -> b) -> SP a b f ()
+> sppure f = cloop
+>  where
+>   cloop = consume () ploop (deliver ())
+>   ploop x = produce (f x) (const cloop) (deliver ())
+
+> -- | A simple identity processor, equivalent to 'sppure id'.
+
+> spid :: SP a a f ()
+> spid = cloop
+>  where
+>   cloop = consume () ploop (deliver ())
+>   ploop x = produce x (const cloop) (deliver ())
+
+> -- | A simple list flattening processor requests.
+
+> spconcat :: SP [a] a f [a]
+> spconcat = cloop
+>  where
+>   cloop = consume () ploop (deliver [])
+>   ploop (x:xs) = produce x (const $ ploop xs) (deliver xs)
+>   ploop [] = cloop
+
+> -- | A processor that folds an entire stream into a single value.
+
+> spfold :: (Functor f, Monoid a) => SP a a f ()
+> spfold = cloop mempty
+>  where
+>   cloop r = consume () (cloop . mappend r) (emit_ r)
+
+> -- | A processor that folds an entire stream into a single value.
+
+> spfoldl :: (b -> a -> b) -> b -> SP a b f ()
+> spfoldl f = cloop
+>  where
+>   cloop r = consume () (cloop . f r) (emit_ r)
+
+> -- | A processor that folds an entire stream into a single value.
+
+> spfoldr :: (a -> b -> b) -> b -> SP a b f ()
+> spfoldr f = cloop
+>  where
+>   cloop r = consume () (cloop . flip f r) (emit_ r)
+
