diff --git a/Control/Concurrent/Configuration.hs b/Control/Concurrent/Configuration.hs
--- a/Control/Concurrent/Configuration.hs
+++ b/Control/Concurrent/Configuration.hs
@@ -1,5 +1,5 @@
 {- 
-    Copyright 2008-2010 Mario Blazevic
+    Copyright 2008-2013 Mario Blazevic
 
     This file is part of the Streaming Component Combinators (SCC) project.
 
@@ -25,9 +25,9 @@
 module Control.Concurrent.Configuration
    (-- * The Component type
     Component (..),
-    -- * Utility functions
+    -- ** Utility functions
     showComponentTree,
-    -- * Constructors
+    -- ** Constructors
     atomic, lift, liftParallelPair, liftSequentialPair, parallelRouterAndBranches, recursiveComponentTree
     )
 where
diff --git a/Control/Concurrent/SCC/Coercions.hs b/Control/Concurrent/SCC/Coercions.hs
--- a/Control/Concurrent/SCC/Coercions.hs
+++ b/Control/Concurrent/SCC/Coercions.hs
@@ -1,5 +1,5 @@
 {- 
-    Copyright 2009-2010 Mario Blazevic
+    Copyright 2009-2012 Mario Blazevic
 
     This file is part of the Streaming Component Combinators (SCC) project.
 
@@ -32,8 +32,11 @@
 import Prelude hiding ((.))
 import Control.Category ((.))
 import Control.Monad (liftM)
+import Data.Monoid (Monoid(mempty))
 import Data.Text (Text, pack, unpack)
-   
+
+import Control.Monad.Coroutine (sequentialBinder)
+
 import Control.Concurrent.SCC.Streams
 import Control.Concurrent.SCC.Types
 
@@ -42,41 +45,56 @@
 class Coercible x y where
    -- | A 'Transducer' that converts a stream of one type to another.
    coerce :: Monad m => Transducer m x y
-   adaptConsumer :: Monad m => Consumer m y r -> Consumer m x r
+   adaptConsumer :: (Monad m, Monoid x, Monoid y) => Consumer m y r -> Consumer m x r
    adaptConsumer consumer = isolateConsumer $ \source-> liftM snd $ pipe (transduce coerce source) (consume consumer)
-   adaptProducer :: Monad m => Producer m x r -> Producer m y r
+   adaptProducer :: (Monad m, Monoid x, Monoid y) => Producer m x r -> Producer m y r
    adaptProducer producer = isolateProducer $ \sink-> liftM fst $ pipe (produce producer) (flip (transduce coerce) sink)
 
 instance Coercible x x where
-   coerce = Transducer pour
+   coerce = Transducer pour_
    adaptConsumer = id
    adaptProducer = id
 
-instance Coercible Char Text where
+instance Monoid x => Coercible [x] x where
+   coerce = statelessTransducer id
+
+instance Coercible [Char] [Text] where
    coerce = Transducer (mapStreamChunks ((:[]) . pack))
 
-instance Coercible Text Char where
+instance Coercible String Text where
+   coerce = Transducer (mapStreamChunks pack)
+
+instance Coercible [Text] [Char] where
    coerce = statelessTransducer unpack
 
-instance Coercible x y => Coercible [x] y where
-   coerce = coerce . statelessTransducer id
+instance Coercible Text String where
+   coerce = statelessChunkTransducer unpack
 
-instance Coercible x y => Coercible (Markup b x) y where
-   coerce = coerce . statelessTransducer unmark
+instance Coercible [x] [y] => Coercible [[x]] [y] where
+   coerce = compose sequentialBinder (statelessTransducer id) coerce
+
+instance Coercible [x] [y] => Coercible [Markup b x] [y] where
+   coerce = compose sequentialBinder (statelessTransducer unmark) coerce
       where unmark (Content x) = [x]
             unmark (Markup _) = []
 
+instance (Monoid x, Monoid y, Coercible x y) => Coercible [Markup b x] y where
+   coerce = compose sequentialBinder (statelessTransducer unmark) coerce
+      where unmark (Content x) = x
+            unmark (Markup _) = mempty
+
 -- | Adjusts the argument splitter to split the stream of a data type 'Isomorphic' to the type it was meant to split.
-adaptSplitter :: forall m x y b. (Monad m, Coercible x y, Coercible y x) => Splitter m x b -> Splitter m y b
+adaptSplitter :: forall m x y b. (Monad m, Monoid x, Monoid y, Coercible x y, Coercible y x) =>
+                 Splitter m x -> Splitter m y
 adaptSplitter sx = 
-   isolateSplitter $ \source true false edge->
+   isolateSplitter $ \source true false->
    pipe 
       (transduce coerce source) 
       (\source'-> 
         pipe 
            (\true'-> 
              pipe
-                (\false'-> split sx source' true' false' edge) 
+                (\false'-> split sx source' true' false') 
                 (flip (transduce coerce) false))
            (flip (transduce coerce) true))
       >> return ()
diff --git a/Control/Concurrent/SCC/Combinators.hs b/Control/Concurrent/SCC/Combinators.hs
--- a/Control/Concurrent/SCC/Combinators.hs
+++ b/Control/Concurrent/SCC/Combinators.hs
@@ -1,5 +1,5 @@
-{- 
-    Copyright 2008-2010 Mario Blazevic
+{-
+    Copyright 2008-2013 Mario Blazevic
 
     This file is part of the Streaming Component Combinators (SCC) project.
 
@@ -15,7 +15,8 @@
 -}
 
 {-# LANGUAGE ScopedTypeVariables, RankNTypes, KindSignatures, EmptyDataDecls,
-             MultiParamTypeClasses, FlexibleContexts, FlexibleInstances, FunctionalDependencies, TypeFamilies #-}
+             MultiParamTypeClasses, FlexibleContexts, FlexibleInstances, OverlappingInstances,
+             FunctionalDependencies, TypeFamilies #-}
 {-# OPTIONS_HADDOCK hide #-}
 
 -- | The "Combinators" module defines combinators applicable to values of the 'Transducer' and 'Splitter' types defined
@@ -24,7 +25,7 @@
 module Control.Concurrent.SCC.Combinators (
    -- * Consumer, producer, and transducer combinators
    consumeBy, prepend, append, substitute,
-   PipeableComponentPair (compose), JoinableComponentPair (join, sequence),
+   JoinableComponentPair (join, sequence),
    -- * Splitter combinators
    sNot,
    -- ** Pseudo-logic flow combinators
@@ -66,21 +67,25 @@
    -- ** positional splitters
    startOf, endOf, between,
    -- * Parser support
-   splitterToMarker, parserToSplitter, parseRegions, parseNestedRegions, parseEachNestedRegion,
+   splitterToMarker, splittersToPairMarker, parserToSplitter, parseRegions,
    -- * Helper functions
    groupMarks, findsTrueIn, findsFalseIn, teeConsumers
    )
 where
-
-import Prelude hiding (even, last, sequence, head)
-import Control.Monad (liftM, when)
+   
+import Prelude hiding (drop, even, last, length, map, null, sequence)
+import Control.Monad (liftM, void, when)
 import Control.Monad.Trans.Class (lift)
 import Data.Maybe (isJust, mapMaybe)
+import Data.Monoid (Monoid, mempty, mconcat)
 import qualified Data.Foldable as Foldable
+import qualified Data.List as List (map)
 import qualified Data.Sequence as Seq
-import Data.Sequence (Seq, (|>), (><), ViewL (EmptyL, (:<)))
+import Data.Sequence (Seq, (<|), (|>), (><), ViewL (EmptyL, (:<)))
 
 import Control.Monad.Coroutine
+import Data.Monoid.Null (MonoidNull(null))
+import Data.Monoid.Factorial (FactorialMonoid, length, drop, map)
 
 import Control.Concurrent.SCC.Streams
 import Control.Concurrent.SCC.Types
@@ -90,54 +95,12 @@
 consumeBy :: forall m x y r. (Monad m) => Consumer m x r -> Transducer m x y
 consumeBy c = Transducer $ \ source _sink -> consume c source >> return ()
 
--- | Class 'PipeableComponentPair' applies to any two components that can be combined into a third component with the
--- following properties:
---
---    * The input of the result, if any, becomes the input of the first component.
---
---    * The output produced by the first child component is consumed by the second child component.
---
---    * The result output, if any, is the output of the second component.
-class PipeableComponentPair (m :: * -> *) w c1 c2 c3 | c1 c2 -> c3, c1 c3 -> c2, c2 c3 -> c2,
-                                                       c1 -> m w, c2 -> m w, c3 -> m
-   where compose :: PairBinder m -> c1 -> c2 -> c3
-
-instance forall m x. Monad m => PipeableComponentPair m x (Producer m x ()) (Consumer m x ()) (Performer m ())
-   where compose binder p c = let performPipe :: Coroutine Naught m ((), ())
-                                  performPipe = pipeG binder (produce p) (consume c)
-                              in Performer (runCoroutine performPipe >> return ())
-
-instance Monad m => PipeableComponentPair m y (Transducer m x y) (Consumer m y r) (Consumer m x r)
-   where compose binder t c = isolateConsumer $ \source-> 
-                              liftM snd $
-                              pipeG binder
-                                 (transduce t source)
-                                 (consume c)
-
-instance Monad m => PipeableComponentPair m x (Producer m x r) (Transducer m x y) (Producer m y r)
-   where compose binder p t = isolateProducer $ \sink-> 
-                              liftM fst $
-                              pipeG binder
-                                 (produce p)
-                                 (\source-> transduce t source sink)
-
-instance Monad m => PipeableComponentPair m y (Transducer m x y) (Transducer m y z) (Transducer m x z)
-   where compose binder t1 t2 = 
-            isolateTransducer $ \source sink-> 
-            pipeG binder (transduce t1 source) (\source'-> transduce t2 source' sink)
-            >> return ()
-
 class CompatibleSignature c cons (m :: * -> *) input output | c -> cons m
 
-class AnyListOrUnit c
-
-instance AnyListOrUnit [x]
-instance AnyListOrUnit ()
-
-instance (AnyListOrUnit x, AnyListOrUnit y) => CompatibleSignature (Performer m r)    (PerformerType r)  m x y
-instance AnyListOrUnit y                    => CompatibleSignature (Consumer m x r)   (ConsumerType r)   m [x] y
-instance AnyListOrUnit y                    => CompatibleSignature (Producer m x r)   (ProducerType r)   m y [x]
-instance                                       CompatibleSignature (Transducer m x y)  TransducerType    m [x] [y]
+instance CompatibleSignature (Performer m r)    (PerformerType r)  m x y
+instance CompatibleSignature (Consumer m x r)   (ConsumerType r)   m x y
+instance CompatibleSignature (Producer m x r)   (ProducerType r)   m y x
+instance CompatibleSignature (Transducer m x y)  TransducerType    m x y
 
 data PerformerType r
 data ConsumerType r
@@ -163,21 +126,21 @@
       sequence :: c1 -> c2 -> c3
 
 instance forall m x r1 r2. Monad m =>
-   JoinableComponentPair (ProducerType r1) (ProducerType r2) (ProducerType r2) m () [x]
+   JoinableComponentPair (ProducerType r1) (ProducerType r2) (ProducerType r2) m () x
                          (Producer m x r1) (Producer m x r2) (Producer m x r2)
    where sequence p1 p2 = Producer $ \sink-> produce p1 sink >> produce p2 sink
 
 instance forall m x. Monad m =>
-   JoinableComponentPair (ConsumerType ()) (ConsumerType ()) (ConsumerType ()) m [x] ()
+   JoinableComponentPair (ConsumerType ()) (ConsumerType ()) (ConsumerType ()) m x ()
                          (Consumer m x ()) (Consumer m x ()) (Consumer m x ())
    where join binder c1 c2 = Consumer (liftM (const ()) . teeConsumers binder (consume c1) (consume c2))
          sequence c1 c2 = Consumer $ \source->
-                          teeConsumers sequentialBinder (consume c1) getList source
-                          >>= \((), list)-> pipe (putList list) (consume c2)
+                          teeConsumers sequentialBinder (consume c1) getAll source
+                          >>= \((), list)-> pipe (flip putChunk list) (consume c2)
                           >> return ()
 
-instance forall m x y. Monad m =>
-   JoinableComponentPair TransducerType TransducerType TransducerType m [x] [y]
+instance forall m x y. (Monad m, Monoid x, Monoid y) =>
+   JoinableComponentPair TransducerType TransducerType TransducerType m x y
                          (Transducer m x y) (Transducer m x y) (Transducer m x y)
    where join binder t1 t2 = isolateTransducer $ \source sink->
                              pipe
@@ -185,12 +148,12 @@
                                               (\source'-> transduce t1 source' sink)
                                               (\source'-> transduce t2 source' buffer)
                                               source)
-                                getList
-                             >>= \(_, list)-> putList list sink
+                                getAll
+                             >>= \(_, list)-> putChunk sink list
                              >> return ()
          sequence t1 t2 = isolateTransducer $ \source sink->
-                          teeConsumers sequentialBinder (flip (transduce t1) sink) getList source
-                          >>= \(_, list)-> pipe (putList list) (\source'-> transduce t2 source' sink)
+                          teeConsumers sequentialBinder (flip (transduce t1) sink) getAll source
+                          >>= \(_, list)-> pipe (flip putChunk list) (\source'-> transduce t2 source' sink)
                           >> return ()
 
 instance forall m r1 r2. Monad m =>
@@ -200,31 +163,31 @@
          sequence p1 p2 = Performer $ perform p1 >> perform p2
 
 instance forall m x r1 r2. Monad m =>
-   JoinableComponentPair (PerformerType r1) (ProducerType r2) (ProducerType r2) m () [x]
+   JoinableComponentPair (PerformerType r1) (ProducerType r2) (ProducerType r2) m () x
                          (Performer m r1) (Producer m x r2) (Producer m x r2)
    where join binder pe pr = Producer $ \sink-> liftBinder binder (const return) (lift (perform pe)) (produce pr sink)
          sequence pe pr = Producer $ \sink-> lift (perform pe) >> produce pr sink
 
 instance forall m x r1 r2. Monad m =>
-   JoinableComponentPair (ProducerType r1) (PerformerType r2) (ProducerType r2) m () [x]
+   JoinableComponentPair (ProducerType r1) (PerformerType r2) (ProducerType r2) m () x
                          (Producer m x r1) (Performer m r2) (Producer m x r2)
    where join binder pr pe = Producer $ \sink-> liftBinder binder (const return) (produce pr sink) (lift (perform pe))
          sequence pr pe = Producer $ \sink-> produce pr sink >> lift (perform pe)
 
 instance forall m x r1 r2. Monad m =>
-   JoinableComponentPair (PerformerType r1) (ConsumerType r2) (ConsumerType r2) m [x] ()
+   JoinableComponentPair (PerformerType r1) (ConsumerType r2) (ConsumerType r2) m x ()
                          (Performer m r1) (Consumer m x r2) (Consumer m x r2)
    where join binder p c = Consumer $ \source-> liftBinder binder (const return) (lift (perform p)) (consume c source)
          sequence p c = Consumer $ \source-> lift (perform p) >> consume c source
 
 instance forall m x r1 r2. Monad m =>
-   JoinableComponentPair (ConsumerType r1) (PerformerType r2) (ConsumerType r2) m [x] ()
+   JoinableComponentPair (ConsumerType r1) (PerformerType r2) (ConsumerType r2) m x ()
                          (Consumer m x r1) (Performer m r2) (Consumer m x r2)
    where join binder c p = Consumer $ \source-> liftBinder binder (const return) (consume c source) (lift (perform p))
          sequence c p = Consumer $ \source-> consume c source >> lift (perform p)
 
 instance forall m x y r. Monad m =>
-   JoinableComponentPair (PerformerType r) TransducerType TransducerType m [x] [y]
+   JoinableComponentPair (PerformerType r) TransducerType TransducerType m x y
                          (Performer m r) (Transducer m x y) (Transducer m x y)
    where join binder p t = 
             Transducer $ \ source sink -> 
@@ -232,7 +195,7 @@
          sequence p t = Transducer $ \ source sink -> lift (perform p) >> transduce t source sink
 
 instance forall m x y r. Monad m
-   => JoinableComponentPair TransducerType (PerformerType r) TransducerType m [x] [y]
+   => JoinableComponentPair TransducerType (PerformerType r) TransducerType m x y
                             (Transducer m x y) (Performer m r) (Transducer m x y)
    where join binder t p = 
             Transducer $ \ source sink -> 
@@ -241,56 +204,56 @@
                                                          _ <- lift (perform p)
                                                          return result
 
-instance forall m x y. Monad m =>
-   JoinableComponentPair (ProducerType ()) TransducerType TransducerType m [x] [y]
+instance forall m x y. (Monad m, Monoid x, Monoid y) =>
+   JoinableComponentPair (ProducerType ()) TransducerType TransducerType m x y
                          (Producer m y ()) (Transducer m x y) (Transducer m x y)
    where join binder p t = 
             isolateTransducer $ \source sink->
-            pipe (\buffer-> liftBinder binder (const return) (produce p sink) (transduce t source buffer)) getList
-            >>= \(_, out)-> putList out sink >> return ()
+            pipe (\buffer-> liftBinder binder (const return) (produce p sink) (transduce t source buffer)) getAll
+            >>= \(_, out)-> putChunk sink out >> return ()
          sequence p t = Transducer $ \ source sink -> produce p sink >> transduce t source sink
 
-instance forall m x y. Monad m =>
-   JoinableComponentPair TransducerType (ProducerType ()) TransducerType m [x] [y]
+instance forall m x y. (Monad m, Monoid x, Monoid y) =>
+   JoinableComponentPair TransducerType (ProducerType ()) TransducerType m x y
                          (Transducer m x y) (Producer m y ()) (Transducer m x y)
    where join binder t p =
             isolateTransducer $ \source sink->
-            pipe (\buffer-> liftBinder binder (const . return) (transduce t source sink) (produce p buffer)) getList
-            >>= \(_, out)-> putList out sink >> return ()
+            pipe (\buffer-> liftBinder binder (const . return) (transduce t source sink) (produce p buffer)) getAll
+            >>= \(_, out)-> putChunk sink out >> return ()
          sequence t p = Transducer $ \ source sink -> do result <- transduce t source sink
                                                          produce p sink
                                                          return result
 
-instance forall m x y. Monad m =>
-   JoinableComponentPair (ConsumerType ()) TransducerType TransducerType m [x] [y]
+instance forall m x y. (Monad m, Monoid x, Monoid y) =>
+   JoinableComponentPair (ConsumerType ()) TransducerType TransducerType m x y
                          (Consumer m x ()) (Transducer m x y) (Transducer m x y)
    where join binder c t = 
             isolateTransducer $ \source sink->
             teeConsumers binder (consume c) (\source'-> transduce t source' sink) source
             >> return ()
          sequence c t = isolateTransducer $ \source sink->
-                        teeConsumers sequentialBinder (consume c) getList source
-                        >>= \(_, list)-> pipe (putList list) (\source'-> transduce t source' sink)
+                        teeConsumers sequentialBinder (consume c) getAll source
+                        >>= \(_, list)-> pipe (flip putChunk list) (\source'-> transduce t source' sink)
                         >> return ()
 
-instance forall m x y. Monad m =>
-   JoinableComponentPair TransducerType (ConsumerType ()) TransducerType m [x] [y]
+instance forall m x y. (Monad m, Monoid x, Monoid y) =>
+   JoinableComponentPair TransducerType (ConsumerType ()) TransducerType m x y
                          (Transducer m x y) (Consumer m x ()) (Transducer m x y)
    where join binder t c = join binder c t
          sequence t c = isolateTransducer $ \source sink->
-                        teeConsumers sequentialBinder (\source'-> transduce t source' sink) getList source
-                        >>= \(_, list)-> pipe (putList list) (consume c)
+                        teeConsumers sequentialBinder (\source'-> transduce t source' sink) getAll source
+                        >>= \(_, list)-> pipe (flip putChunk list) (consume c)
                         >> return ()
 
 instance forall m x y. Monad m =>
-   JoinableComponentPair (ProducerType ()) (ConsumerType ()) TransducerType m [x] [y]
+   JoinableComponentPair (ProducerType ()) (ConsumerType ()) TransducerType m x y
                          (Producer m y ()) (Consumer m x ()) (Transducer m x y)
    where join binder p c = Transducer $ 
                            \ source sink -> liftBinder binder (\ _ _ -> return ()) (produce p sink) (consume c source)
          sequence p c = Transducer $ \ source sink -> produce p sink >> consume c source
 
 instance forall m x y. Monad m =>
-   JoinableComponentPair (ConsumerType ()) (ProducerType ()) TransducerType m [x] [y]
+   JoinableComponentPair (ConsumerType ()) (ProducerType ()) TransducerType m x y
                          (Consumer m x ()) (Producer m y ()) (Transducer m x y)
    where join binder c p = join binder p c
          sequence c p = Transducer $ \ source sink -> consume c source >> produce p sink
@@ -299,7 +262,7 @@
 -- input through unmodified, except for prepending the output of the argument producer to it. The following law holds: @
 -- 'prepend' /prefix/ = 'join' ('substitute' /prefix/) 'Control.Category.id' @
 prepend :: forall m x r. Monad m => Producer m x r -> Transducer m x x
-prepend prefixProducer = Transducer $ \ source sink -> produce prefixProducer sink >> pour source sink
+prepend prefixProducer = Transducer $ \ source sink -> produce prefixProducer sink >> pour_ source sink
 
 -- | Combinator 'append' converts the given producer to a 'Control.Concurrent.SCC.Types.Transducer' that passes all its
 -- input through unmodified, finally appending the output of the argument producer to it. The following law holds: @
@@ -309,139 +272,95 @@
 
 -- | The 'substitute' combinator converts its argument producer to a 'Control.Concurrent.SCC.Types.Transducer' that
 -- produces the same output, while consuming its entire input and ignoring it.
-substitute :: forall m x y r. Monad m => Producer m y r -> Transducer m x y
-substitute feed = Transducer $ \ source sink -> mapMStream_ (const $ return ()) source >> produce feed sink >> return ()
+substitute :: forall m x y r. (Monad m, Monoid x) => Producer m y r -> Transducer m x y
+substitute feed = Transducer $ 
+                  \ source sink -> mapMStreamChunks_ (const $ return ()) source >> produce feed sink >> return ()
 
 -- | The 'sNot' (streaming not) combinator simply reverses the outputs of the argument splitter. In other words, data
 -- that the argument splitter sends to its /true/ sink goes to the /false/ sink of the result, and vice versa.
-sNot :: forall m x b. Monad m => Splitter m x b -> Splitter m x b
+sNot :: forall m x. (Monad m, Monoid x) => Splitter m x -> Splitter m x
 sNot splitter = isolateSplitter s
-   where s :: forall d. Functor d => Source m d x -> Sink m d x -> Sink m d x -> Sink m d b -> Coroutine d m ()
-         s source true false _edge = split splitter source false true (nullSink :: Sink m d b)
+   where s :: forall d. Functor d => Source m d x -> Sink m d x -> Sink m d x -> Coroutine d m ()
+         s source true false = split splitter source false true
 
 -- | The 'sAnd' combinator sends the /true/ sink output of its left operand to the input of its right operand for
 -- further splitting. Both operands' /false/ sinks are connected to the /false/ sink of the combined splitter, but any
 -- input value to reach the /true/ sink of the combined component data must be deemed true by both splitters.
-sAnd :: forall m x b1 b2. Monad m => PairBinder m -> Splitter m x b1 -> Splitter m x b2 -> Splitter m x (b1, b2)
+sAnd :: forall m x. (Monad m, Monoid x) => PairBinder m -> Splitter m x -> Splitter m x -> Splitter m x
 sAnd binder s1 s2 =
-   isolateSplitter $ \ source true false edge ->
-   liftM (fst . fst) $
-   pipe
-      (\edges-> pipeG binder
-                   (\true'-> split s1 source true' false (mapSink Left edges))
-                   (\source'-> split s2 source' true false (mapSink Right edges)))
-      (flip intersectRegions edge)
-
-intersectRegions :: forall m a1 a2 d b1 b2. Monad m => OpenTransducer m a1 a2 d (Either b1 b2) (b1, b2) ()
-intersectRegions source sink = next Nothing Nothing
-   where next lastLeft lastRight = getWith
-                                      (either
-                                          (flip pair lastRight . Just)
-                                          (pair lastLeft . Just))
-                                      source
-         pair (Just x) (Just y) = put sink (x, y)
-                                  >> next Nothing Nothing
-         pair l r = next l r
+   isolateSplitter $ \ source true false ->
+   liftM fst $
+   pipeG binder
+      (\true'-> split s1 source true' false)
+      (\source'-> split s2 source' true false)
 
 -- | A 'sOr' combinator's input value can reach its /false/ sink only by going through both argument splitters' /false/
 -- sinks.
-sOr :: forall m x b1 b2. Monad m => PairBinder m -> Splitter m x b1 -> Splitter m x b2 -> Splitter m x (Either b1 b2)
+sOr :: forall m x. (Monad m, Monoid x) => PairBinder m -> Splitter m x -> Splitter m x -> Splitter m x
 sOr binder s1 s2 = 
-   isolateSplitter $ \ source true false edge ->
+   isolateSplitter $ \ source true false ->
    liftM fst $
    pipeG binder
-      (\false'-> split s1 source true false' (mapSink Left edge))
-      (\source'-> split s2 source' true false (mapSink Right edge))
+      (\false'-> split s1 source true false')
+      (\source'-> split s2 source' true false)
 
 -- | Combinator 'pAnd' is a pairwise logical conjunction of two splitters run in parallel on the same input.
-pAnd :: forall m x b1 b2. Monad m => PairBinder m -> Splitter m x b1 -> Splitter m x b2 -> Splitter m x (b1, b2)
-pAnd binder s1 s2 = 
-   isolateSplitter $ \ source true false edge ->
-   pipeG binder
-      (transduce (splittersToPairMarker binder s1 s2) source)
-      (\source'-> let next l r = getWith (test l r) source'
-                      test l r (Left (x, t1, t2)) = 
-                         (if t1 && t2 then put true x else put false x)
-                         >> next (if t1 then l else Nothing) (if t2 then r else Nothing)
-                      test _ Nothing (Right (Left l)) = next (Just l) Nothing
-                      test _ (Just r) (Right (Left l)) = put edge (l, r) >> next (Just l) (Just r)
-                      test Nothing _ (Right (Right r)) = next Nothing (Just r)
-                      test (Just l) _ (Right (Right r)) = put edge (l, r) >> next (Just l) (Just r)
-                  in next Nothing Nothing)
-      >> return ()
+pAnd :: forall m x. (Monad m, FactorialMonoid x) => PairBinder m -> Splitter m x -> Splitter m x -> Splitter m x
+pAnd = zipSplittersWith (&&)
 
 -- | Combinator 'pOr' is a pairwise logical disjunction of two splitters run in parallel on the same input.
-pOr :: forall m x b1 b2. Monad m => PairBinder m -> Splitter m x b1 -> Splitter m x b2 -> Splitter m x (Either b1 b2)
-pOr = zipSplittersWith (||) pour
+pOr :: forall m x. (Monad m, FactorialMonoid x) => PairBinder m -> Splitter m x -> Splitter m x -> Splitter m x
+pOr = zipSplittersWith (||)
 
-ifs :: forall c m x b. (Monad m, Branching c m x ()) => PairBinder m -> Splitter m x b -> c -> c -> c
+ifs :: forall c m x. (Monad m, Branching c m x ()) => PairBinder m -> Splitter m x -> c -> c -> c
 ifs binder s c1 c2 = combineBranches if' binder c1 c2
    where if' :: forall d. PairBinder m -> (forall a d'. AncestorFunctor d d' => OpenConsumer m a d' x ()) ->
                 (forall a d'. AncestorFunctor d d' => OpenConsumer m a d' x ()) ->
                 forall a. OpenConsumer m a d x ()
          if' binder' c1' c2' source = splitInputToConsumers binder' s source c1' c2'
 
-wherever :: forall m x b. Monad m => PairBinder m -> Transducer m x x -> Splitter m x b -> Transducer m x x
+wherever :: forall m x. (Monad m, Monoid x) => PairBinder m -> Transducer m x x -> Splitter m x -> Transducer m x x
 wherever binder t s = isolateTransducer wherever'
    where wherever' :: forall d. Functor d => Source m d x -> Sink m d x -> Coroutine d m ()
          wherever' source sink = pipeG binder
-                                    (\true-> split s source true sink (nullSink :: Sink m d b))
+                                    (\true-> split s source true sink)
                                     (flip (transduce t) sink)
                                  >> return ()
 
-unless :: forall m x b. Monad m => PairBinder m -> Transducer m x x -> Splitter m x b -> Transducer m x x
+unless :: forall m x. (Monad m, Monoid x) => PairBinder m -> Transducer m x x -> Splitter m x -> Transducer m x x
 unless binder t s = wherever binder t (sNot s)
 
-select :: forall m x b. Monad m => Splitter m x b -> Transducer m x x
+select :: forall m x. (Monad m, Monoid x) => Splitter m x -> Transducer m x x
 select s = isolateTransducer t 
    where t :: forall d. Functor d => Source m d x -> Sink m d x -> Coroutine d m ()
-         t source sink = split s source sink (nullSink :: Sink m d x) (nullSink :: Sink m d b)
+         t source sink = split s source sink (nullSink :: Sink m d x)
 
 -- | Converts a splitter into a parser.
-parseRegions :: forall m x b. Monad m => Splitter m x b -> Parser m x b
+parseRegions :: forall m x. (Monad m, MonoidNull x) => Splitter m x -> Parser m x ()
 parseRegions s = isolateTransducer $ \source sink->
                     pipe
                        (transduce (splitterToMarker s) source)
                        (\source'-> concatMapAccumStream wrap Nothing source' sink 
                                    >>= maybe (return ()) (put sink . flush))
                     >> return ()
-   where wrap Nothing (Left (x, _)) = (Nothing, [Content x])
-         wrap (Just p) (Left (x, False)) = (Nothing, [flush p, Content x])
-         wrap (Just (b, t)) (Left (x, True)) = (Just (b, True), if t then [Content x] else [Markup (Start b), Content x])
-         wrap (Just p) (Right b') = (Just (b', False), [flush p])
-         wrap Nothing (Right b) = (Just (b, False), [])
+   where wrap Nothing (x, False) = (Nothing, if null x then [] else [Content x])
+         wrap Nothing (x, True) | null x = (Just ((), False), [])
+                                | otherwise = (Just ((), True), [Markup (Start ()), Content x])
+         wrap (Just p) (x, False) = (Nothing, if null x then [flush p] else [flush p, Content x])
+         wrap (Just (b, t)) (x, True) = (Just (b, True), if t then [Content x] else [Markup (Start b), Content x])
          flush (b, t) = Markup $ (if t then End else Point) b
 
--- | Converts a boundary-marking splitter into a parser.
-parseNestedRegions :: forall m x b. Monad m => Splitter m x (Boundary b) -> Parser m x b
-parseNestedRegions s = isolateTransducer $ \source sink->
-                       split s source (mapSink Content sink) (mapSink Content sink) (mapSink Markup sink)
-
--- | Converts a boundary-marking splitter into a parser.
-parseEachNestedRegion :: forall m x y b. Monad m =>
-                         PairBinder m -> Splitter m x (Boundary b) -> Transducer m x y -> Transducer m x (Markup b y)
-parseEachNestedRegion binder s t =
-   isolateTransducer $ \source sink->
-   let transformContent contentSource = transduce t contentSource (mapSink Content sink)
-   in pipeG binder
-         (transduce (splitterToMarker s) source)
-         (flip groupMarks (maybe transformContent (\mark group-> maybe (return ()) (put sink . Markup) mark
-                                                                 >> transformContent group)))
-      >> return ()
-
 -- | The recursive combinator 'while' feeds the true sink of the argument splitter back to itself, modified by the
 -- argument transducer. Data fed to the splitter's false sink is passed on unmodified.
-while :: forall m x b. Monad m => 
-         PairBinder m -> Transducer m x x -> Splitter m x b -> Transducer m x x -> Transducer m x x
+while :: forall m x. (Monad m, MonoidNull x) => 
+         PairBinder m -> Transducer m x x -> Splitter m x -> Transducer m x x -> Transducer m x x
 while binder t s whileRest = isolateTransducer while'
    where while' :: forall d. Functor d => Source m d x -> Sink m d x -> Coroutine d m ()
          while' source sink =
             pipeG binder
-               (\true'-> split s source true' sink (nullSink :: Sink m d b))
-               (\source'-> peek source'
-                           >>= maybe 
-                                  (return ())
-                                  (\_-> transduce (compose binder t whileRest) source' sink))
+               (\true'-> split s source true' sink)
+               (\source'-> getRead readEof source'
+                           >>= flip (when . not) (transduce (compose binder t whileRest) source' sink))
             >> return ()
 
 -- | The recursive combinator 'nestedIn' combines two splitters into a mutually recursive loop acting as a single
@@ -450,26 +369,24 @@
 -- hierarchically structured streams. If we gave it some input containing a flat sequence of values, and assuming both
 -- component splitters are deterministic and stateless, an input value would either not loop at all or it would loop
 -- forever.
-nestedIn :: forall m x b. Monad m => 
-            PairBinder m -> Splitter m x b -> Splitter m x b -> Splitter m x b -> Splitter m x b
+nestedIn :: forall m x. (Monad m, MonoidNull x) => 
+            PairBinder m -> Splitter m x -> Splitter m x -> Splitter m x -> Splitter m x
 nestedIn binder s1 s2 nestedRest =
-   isolateSplitter $ \ source true false edge ->
+   isolateSplitter $ \ source true false ->
    liftM fst $
       pipeG binder
-         (\false'-> split s1 source true false' edge)
+         (\false'-> split s1 source true false')
          (\source'-> pipe
                         (\true'-> splitInput s2 source' true' false)
-                        (\source''-> peek source''
-                                     >>= maybe
-                                            (return ())
-                                            (\_-> split nestedRest source'' true false edge)))
+                        (\source''-> getRead readEof source''
+                                     >>= flip (when . not) (split nestedRest source'' true false)))
 
 -- | The 'foreach' combinator is similar to the combinator 'ifs' in that it combines a splitter and two transducers into
 -- another transducer. However, in this case the transducers are re-instantiated for each consecutive portion of the
 -- input as the splitter chunks it up. Each contiguous portion of the input that the splitter sends to one of its two
 -- sinks gets transducered through the appropriate argument transducer as that transducer's whole input. As soon as the
 -- contiguous portion is finished, the transducer gets terminated.
-foreach :: forall m x b c. (Monad m, Branching c m x ()) => PairBinder m -> Splitter m x b -> c -> c -> c
+foreach :: forall m x c. (Monad m, MonoidNull x, Branching c m x ()) => PairBinder m -> Splitter m x -> c -> c -> c
 foreach binder s c1 c2 = combineBranches foreach' binder c1 c2
    where foreach' :: forall d. PairBinder m -> 
                      (forall a d'. AncestorFunctor d d' => OpenConsumer m a d' x ()) ->
@@ -479,79 +396,75 @@
             liftM fst $
             pipeG binder'
                (transduce (splitterToMarker s) (liftSource source :: Source m d x))
-               (\source'-> groupMarks source' (maybe c2' (const c1')))
+               (\source'-> groupMarks source' (\b-> if b then c1' else c2'))
 
 -- | The 'having' combinator combines two pure splitters into a pure splitter. One splitter is used to chunk the input
 -- into contiguous portions. Its /false/ sink is routed directly to the /false/ sink of the combined splitter. The
 -- second splitter is instantiated and run on each portion of the input that goes to first splitter's /true/ sink. If
 -- the second splitter sends any output at all to its /true/ sink, the whole input portion is passed on to the /true/
 -- sink of the combined splitter, otherwise it goes to its /false/ sink.
-having :: forall m x y b1 b2. (Monad m, Coercible x y) =>
-          PairBinder m -> Splitter m x b1 -> Splitter m y b2 -> Splitter m x b1
+having :: forall m x y. (Monad m, MonoidNull x, MonoidNull y, Coercible x y) =>
+          PairBinder m -> Splitter m x -> Splitter m y -> Splitter m x
 having binder s1 s2 = isolateSplitter s
-   where s :: forall d. Functor d => Source m d x -> Sink m d x -> Sink m d x -> Sink m d b1 -> Coroutine d m ()
-         s source true false edge = pipeG binder
-                                       (transduce (splitterToMarker s1) source)
-                                       (flip groupMarks test)
-                                    >> return ()
-            where test Nothing chunk = pour chunk false
-                  test (Just mb) chunk = 
-                     do chunkBuffer <- getList chunk
-                        (_, maybeFound) <- 
-                           pipe (produce $ adaptProducer $ Producer $ putList chunkBuffer) (findsTrueIn s2)
-                        if isJust maybeFound 
-                           then maybe (return ()) (put edge) mb >> putList chunkBuffer true >> return ()
-                           else putList chunkBuffer false >> return ()
+   where s :: forall d. Functor d => Source m d x -> Sink m d x -> Sink m d x -> Coroutine d m ()
+         s source true false = pipeG binder
+                                  (transduce (splitterToMarker s1) source)
+                                  (flip groupMarks test)
+                               >> return ()
+            where test False chunk = pour_ chunk false
+                  test True chunk =
+                     do chunkBuffer <- getAll chunk
+                        (_, found) <- pipe (produce $ adaptProducer $ Producer $ putAll chunkBuffer) (findsTrueIn s2)
+                        if found
+                           then putChunk true chunkBuffer
+                           else putAll chunkBuffer false
+                        return ()
 
 -- | The 'havingOnly' combinator is analogous to the 'having' combinator, but it succeeds and passes each chunk of the
 -- input to its /true/ sink only if the second splitter sends no part of it to its /false/ sink.
-havingOnly :: forall m x y b1 b2. (Monad m, Coercible x y) =>
-              PairBinder m -> Splitter m x b1 -> Splitter m y b2 -> Splitter m x b1
+havingOnly :: forall m x y. (Monad m, MonoidNull x, MonoidNull y, Coercible x y) =>
+              PairBinder m -> Splitter m x -> Splitter m y -> Splitter m x
 havingOnly binder s1 s2 = isolateSplitter s
-   where s :: forall d. Functor d => Source m d x -> Sink m d x -> Sink m d x -> Sink m d b1 -> Coroutine d m ()
-         s source true false edge = pipeG binder
-                                       (transduce (splitterToMarker s1) source)
-                                       (flip groupMarks test)
-                                    >> return ()
-            where test Nothing chunk = pour chunk false
-                  test (Just mb) chunk = 
-                     do chunkBuffer <- getList chunk
-                        (_, anyFalse) <- 
-                           pipe (produce $ adaptProducer $ Producer $ putList chunkBuffer) (findsFalseIn s2)
+   where s :: forall d. Functor d => Source m d x -> Sink m d x -> Sink m d x -> Coroutine d m ()
+         s source true false = pipeG binder
+                                  (transduce (splitterToMarker s1) source)
+                                  (flip groupMarks test)
+                               >> return ()
+            where test False chunk = pour_ chunk false
+                  test True chunk =
+                     do chunkBuffer <- getAll chunk
+                        (_, anyFalse) <-
+                           pipe (produce $ adaptProducer $ Producer $ putAll chunkBuffer) (findsFalseIn s2)
                         if anyFalse
-                           then putList chunkBuffer false >> return ()
-                           else maybe (return ()) (put edge) mb >> putList chunkBuffer true >> return ()
+                           then putAll chunkBuffer false
+                           else putChunk true chunkBuffer
+                        return ()
 
 -- | The result of combinator 'first' behaves the same as the argument splitter up to and including the first portion of
 -- the input which goes into the argument's /true/ sink. All input following the first true portion goes into the
 -- /false/ sink.
-first :: forall m x b. Monad m => Splitter m x b -> Splitter m x b
+first :: forall m x. (Monad m, MonoidNull x) => Splitter m x -> Splitter m x
 first splitter = wrapMarkedSplitter splitter $
-                 \source true false edge-> 
-                 let true' = mapSink (\(Left (x, True))-> x) true
-                 in pourUntil (either snd (const True)) source (mapSink (\(Left (x, False))-> x) false)
-                    >>= maybe
-                           (return ())
-                           (\x-> either (const $ return ()) (\b-> put edge b >> get source >> return ()) x
-                                 >> pourWhile (either snd (const False)) source true'
-                                 >> mapMaybeStream (either (Just . fst) (const Nothing)) source false)
+                 \source true false->
+                    pourUntil (snd . head) source (markDown false)
+                    >>= Foldable.mapM_
+                           (\_-> pourWhile (snd . head) source (markDown true)
+                                 >> concatMapStream fst source false)
 
 -- | The result of combinator 'uptoFirst' takes all input up to and including the first portion of the input which goes
 -- into the argument's /true/ sink and feeds it to the result splitter's /true/ sink. All the rest of the input goes
 -- into the /false/ sink. The only difference between 'first' and 'uptoFirst' combinators is in where they direct the
 -- /false/ portion of the input preceding the first /true/ part.
-uptoFirst :: forall m x b. Monad m => Splitter m x b -> Splitter m x b
+uptoFirst :: forall m x. (Monad m, MonoidNull x) => Splitter m x -> Splitter m x
 uptoFirst splitter = wrapMarkedSplitter splitter $
-                     \source true false edge->
-                     do (pfx, mx) <- getUntil (either snd (const True)) source
-                        let prefix' = map (\(Left (x, False))-> x) pfx
-                            true' = mapSink (\(Left (x, True))-> x) true
+                     \source true false->
+                     do (pfx, mx) <- getUntil (snd . head) source
+                        let prefix' = mconcat $ List.map (\(x, False)-> x) pfx
                         maybe
-                           (putList prefix' false >> return ())
-                           (\x-> putList prefix' true
-                                 >> either (const $ return ()) (\b-> put edge b >> get source >> return ()) x
-                                 >> pourWhile (either snd (const False)) source true'
-                                 >> mapMaybeStream (either (Just . fst) (const Nothing)) source false)
+                           (putAll prefix' false >> return ())
+                           (\[x]-> putAll prefix' true
+                                   >> pourWhile (snd . head) source (markDown true)
+                                   >> concatMapStream fst source false)
                            mx
 
 -- | The result of the combinator 'last' is a splitter which directs all input to its /false/ sink, up to the last
@@ -559,365 +472,340 @@
 -- the resulting component's /true/ sink.  The splitter returned by the combinator 'last' has to buffer the previous two
 -- portions of its input, because it cannot know if a true portion of the input is the last one until it sees the end of
 -- the input or another portion succeeding the previous one.
-last :: forall m x b. Monad m => Splitter m x b -> Splitter m x b
+last :: forall m x. (Monad m, MonoidNull x) => Splitter m x -> Splitter m x
 last splitter = 
-  wrapMarkedSplitter splitter $ \source true false edge->
-  let true' = mapSink (\(Left (x, _))-> x) true
-      false' = mapSink (\(Left (x, _))-> x) false
-      split1 Nothing = return []
-      split1 (Just (Left ~(_, True))) = split2 Nothing
-      split1 (Just (Right b)) = get source >> split2 (Just b)
-      split2 mb = getUntil (either (not . snd) (const True)) source >>= split3 mb
-      split3 mb (trues, Nothing) = maybe (return ()) (put edge) mb >> putList trues true'
-      split3 mb (trues, Just (Left ~(_, False))) = getUntil (either snd (const True)) source >>= split4 mb trues
-      split3 _ (trues, b@(Just Right{})) = putList trues false' >> split1 b
-      split4 mb ts (fs, Nothing) = maybe (return ()) (put edge) mb >> putList ts true' >> putList fs false'
-      split4 _ ts (fs, x@Just{}) = putList ts false' >> putList fs false' >> split1 x
-  in pourUntil (either snd (const True)) source false' >>= split1 >> return ()
+   wrapMarkedSplitter splitter $ 
+   \source true false->
+   let split1 = getUntil (not . snd . head) source >>= split2
+       split2 (trues, Nothing) = putChunk true (mconcat $ List.map fst trues)
+       split2 (trues, Just [~(_, False)]) = getUntil (snd . head) source >>= split3 trues
+       split3 ts (fs, Nothing) = putChunk true (mconcat $ List.map fst ts) >> putAll (mconcat $ List.map fst fs) false
+       split3 ts (fs, x@Just{}) = putAll (mconcat $ List.map fst ts) false >> putAll (mconcat $ List.map fst fs) false 
+                                  >> split1
+   in pourUntil (snd . head) source (markDown false) 
+      >>= Foldable.mapM_ (const split1)
 
 -- | The result of the combinator 'lastAndAfter' is a splitter which directs all input to its /false/ sink, up to the
 -- last portion of the input which goes to its argument's /true/ sink. That portion and the remainder of the input is
 -- fed to the resulting component's /true/ sink. The difference between 'last' and 'lastAndAfter' combinators is where
 -- they feed the /false/ portion of the input, if any, remaining after the last /true/ part.
-lastAndAfter :: forall m x b. Monad m => Splitter m x b -> Splitter m x b
+lastAndAfter :: forall m x. (Monad m, MonoidNull x) => Splitter m x -> Splitter m x
 lastAndAfter splitter = 
    wrapMarkedSplitter splitter $
-   \source true false edge->
-   let true' = mapSink (\(Left (x, _))-> x) true
-       false' = mapSink (\(Left (x, _))-> x) false
-       split1 Nothing = return []
-       split1 (Just (Left ~(_, True))) = split2 Nothing
-       split1 (Just (Right b)) = get source >> split2 (Just b)
-       split2 mb = getUntil (either (not . snd) (const True)) source >>= split3 mb
-       split3 mb (trues, Nothing) = maybe (return ()) (put edge) mb >> putList trues true'
-       split3 mb (trues, Just (Left ~(_, False))) = getUntil (either snd (const True)) source >>= split4 mb trues
-       split3 _ (trues, b@(Just Right{})) = putList trues false' >> split1 b
-       split4 mb ts (fs, Nothing) = maybe (return ()) (put edge) mb >> putList ts true' >> putList fs true'
-       split4 _ ts (fs, x@Just{}) = putList ts false' >> putList fs false' >> split1 x
-   in pourUntil (either snd (const True)) source false' >>= split1 >> return ()
+   \source true false->
+   let split1 = getUntil (not . snd . head) source >>= split2
+       split2 (trues, Nothing) = putChunk true (mconcat $ List.map fst trues)
+       split2 (trues, Just [~(_, False)]) = getUntil (snd . head) source >>= split3 trues
+       split3 ts (fs, Nothing) = putChunk true (mconcat $ List.map fst ts) >> putChunk true (mconcat $ List.map fst fs)
+       split3 ts (fs, x@Just{}) = putAll (mconcat $ List.map fst ts) false >> putAll (mconcat $ List.map fst fs) false 
+                                  >> split1
+   in pourUntil (snd . head) source (markDown false) 
+      >>= Foldable.mapM_ (const split1)
 
 -- | The 'prefix' combinator feeds its /true/ sink only the prefix of the input that its argument feeds to its /true/
 -- sink.  All the rest of the input is dumped into the /false/ sink of the result.
-prefix :: forall m x b. Monad m => Splitter m x b -> Splitter m x b
-prefix splitter = wrapMarkedSplitter splitter $
-                  \source true false edge->
-                  peek source
-                  >>= maybe
-                         (return ())
-                         (\x0-> either (return . snd) (\x-> put edge x >> get source >> return True) x0
-                                >>= flip when (pourWhile (either snd (const False))
-                                                         source 
-                                                         (mapSink (\(Left (x, True))-> x) true))
-                                >> mapMaybeStream (either (Just . fst) (const Nothing)) source false)
+prefix :: forall m x. (Monad m, MonoidNull x) => Splitter m x -> Splitter m x
+prefix splitter = wrapMarkedSplitter splitter splitMarked
+   where splitMarked :: forall a1 a2 a3 d. (AncestorFunctor a1 d, AncestorFunctor a2 d, AncestorFunctor a3 d,
+                                            AncestorFunctor a1 (SinkFunctor d [(x, Bool)]),
+                                            AncestorFunctor a2 (SourceFunctor d [(x, Bool)])) =>
+                        Source m a1 [(x, Bool)] -> Sink m a2 x -> Sink m a3 x -> Coroutine d m ()
+         splitMarked source true false =
+            pourUntil (not . null . fst . head) source (nullSink :: Sink m d [(x, Bool)])
+            >>= maybe
+                   (return ())
+                   (\[x0]-> when (snd x0) (pourWhile (snd . head) source (markDown true))
+                            >> concatMapStream fst source false)
 
 -- | The 'suffix' combinator feeds its /true/ sink only the suffix of the input that its argument feeds to its /true/
 -- sink.  All the rest of the input is dumped into the /false/ sink of the result.
-suffix :: forall m x b. Monad m => Splitter m x b -> Splitter m x b
+suffix :: forall m x. (Monad m, MonoidNull x) => Splitter m x -> Splitter m x
 suffix splitter = 
    wrapMarkedSplitter splitter $
-   \source true false edge->
-   let true' = mapSink (\(Left (x, _))-> x) true
-       false' = mapSink (\(Left (x, _))-> x) false
-       split0 = pourUntil (either snd (const True)) source false' >>= split1
-       split1 Nothing = return []
-       split1 (Just Left{}) = split2 Nothing
-       split1 (Just (Right b)) = get source >> split2 (Just b)
-       split2 mb = getUntil (either (not . snd) (const True)) source >>= split3 mb
-       split3 mb (trues, Nothing) = maybe (return ()) (put edge) mb >> putList trues true'
-       split3 _ (trues, Just{}) = putList trues false' >> split0
-   in split0 >> return ()
+   \source true false->
+   let split0 = pourUntil (snd . head) source (markDown false)
+                >>= Foldable.mapM_ (const split1)
+       split1 = getUntil (not . snd . head) source >>= split2
+       split2 (trues, Nothing) = putAll (mconcat $ List.map fst trues) true >> return ()
+       split2 (trues, Just [(x, False)]) 
+          | null x = do (_, mr) <- getUntil (not . null . fst . head) source
+                        case mr of Nothing -> putAll (mconcat $ List.map fst trues) true 
+                                              >> return ()
+                                   Just{} -> putAll (mconcat $ List.map fst trues) false 
+                                             >> split0
+          | otherwise = putAll (mconcat $ List.map fst trues) false  >> split0
+   in split0
 
 -- | The 'even' combinator takes every input section that its argument /splitter/ deems /true/, and feeds even ones into
 -- its /true/ sink. The odd sections and parts of input that are /false/ according to its argument splitter are fed to
 -- 'even' splitter's /false/ sink.
-even :: forall m x b. Monad m => Splitter m x b -> Splitter m x b
+even :: forall m x. (Monad m, MonoidNull x) => Splitter m x -> Splitter m x
 even splitter = wrapMarkedSplitter splitter $
-                \source true false edge->
-                let true' = mapSink (\(Left (x, _))-> x) true
-                    false' = mapSink (\(Left (x, _))-> x) false
-                    split0 = pourUntil (either snd (const True)) source false' >>= split1
+                \source true false->
+                let false' = markDown false
+                    split0 = pourUntil (snd . head) source false' >>= split1
                     split1 Nothing = return ()
-                    split1 (Just (Left ~(_, True))) = split2
-                    split1 (Just Right{}) = get source >> split2
-                    split2 = pourUntil (either (not . snd) (const True)) source false' >>= split3
+                    split1 (Just [~(_, True)]) = split2
+                    split2 = pourUntil (not . snd . head) source false' >>= split3
                     split3 Nothing = return ()
-                    split3 (Just (Left ~(_, False))) = pourUntil (either snd (const True)) source false' >>= split4
-                    split3 r@(Just Right{}) = split4 r
+                    split3 (Just [~(_, False)]) = pourUntil (snd . head) source false' >>= split4
                     split4 Nothing = return ()
-                    split4 (Just (Left ~(_, True))) = split5
-                    split4 (Just (Right b)) = put edge b >> get source >> split5
-                    split5 = pourWhile (either snd (const False)) source true' >> split0
+                    split4 (Just [~(_, True)]) = split5
+                    split5 = pourWhile (snd . head) source (markDown true) >> split0
                 in split0
 
 -- | Splitter 'startOf' issues an empty /true/ section at the beginning of every section considered /true/ by its
 -- argument splitter, otherwise the entire input goes into its /false/ sink.
-startOf :: forall m x b. Monad m => Splitter m x b -> Splitter m x (Maybe b)
+startOf :: forall m x. (Monad m, MonoidNull x) => Splitter m x -> Splitter m x
 startOf splitter = wrapMarkedSplitter splitter $
-                   \source _true false edge->
-                   let false' = mapSink (\(Left (x, _))-> x) false
-                       split0 = pourUntil (either snd (const True)) source false' >>= split1
+                   \source true false->
+                   let false' = markDown false
+                       split0 = pourUntil (snd . head) source false' >>= split1
                        split1 Nothing = return ()
-                       split1 (Just (Left ~(_, True))) = put edge Nothing >> split2
-                       split1 (Just (Right b)) = put edge (Just b) >> get source >> split2
-                       split2 = pourUntil (either (not . snd) (const True)) source false' >>= split3
+                       split1 (Just [~(_, True)]) = putChunk true mempty >> split2
+                       split2 = pourUntil (not . snd . head) source false' >>= split3
                        split3 Nothing = return ()
-                       split3 (Just (Left ~(_, False))) = split0
-                       split3 mb@(Just Right{}) = split1 mb
+                       split3 (Just [~(_, False)]) = split0
                    in split0
 
 -- | Splitter 'endOf' issues an empty /true/ section at the end of every section considered /true/ by its argument
 -- splitter, otherwise the entire input goes into its /false/ sink.
-endOf :: forall m x b. Monad m => Splitter m x b -> Splitter m x (Maybe b)
+endOf :: forall m x. (Monad m, MonoidNull x) => Splitter m x -> Splitter m x
 endOf splitter = wrapMarkedSplitter splitter $
-                 \source _true false edge->
-                 let false' = mapSink (\(Left (x, _))-> x) false
-                     split0 = pourUntil (either snd (const True)) source false' >>= split1
+                 \source true false->
+                 let false' = markDown false
+                     split0 = pourUntil (snd . head) source false' >>= split1
                      split1 Nothing = return ()
-                     split1 (Just (Left ~(_, True))) = split2 Nothing
-                     split1 (Just (Right b)) = get source >> split2 (Just b)
-                     split2 mb = pourUntil (either (not . snd) (const True)) source false' 
-                                 >>= (put edge mb >>) . split3
+                     split1 (Just [~(_, True)]) = split2
+                     split2 = pourUntil (not . snd . head) source false'
+                              >>= (putChunk true mempty >>) . split3
                      split3 Nothing = return ()
-                     split3 (Just (Left ~(_, False))) = split0
-                     split3 mb@(Just Right{}) = split1 mb
+                     split3 (Just [~(_, False)]) = split0
                  in split0
 
 -- | Combinator 'followedBy' treats its argument 'Splitter's as patterns components and returns a 'Splitter' that
 -- matches their concatenation. A section of input is considered /true/ by the result iff its prefix is considered
 -- /true/ by argument /s1/ and the rest of the section is considered /true/ by /s2/. The splitter /s2/ is started anew
 -- after every section split to /true/ sink by /s1/.
-followedBy :: forall m x b1 b2. Monad m => PairBinder m -> Splitter m x b1 -> Splitter m x b2 -> Splitter m x (b1, b2)
-followedBy binder s1 s2 = 
-   isolateSplitter $ \ source true false edge ->
+followedBy :: forall m x. (Monad m, FactorialMonoid x) => PairBinder m -> Splitter m x -> Splitter m x -> Splitter m x
+followedBy binder s1 s2 =
+   isolateSplitter $ \ source true false ->
    pipeG binder
       (transduce (splitterToMarker s1) source)
-      (\source'-> let get0 q = case Seq.viewl q
-                               of Seq.EmptyL -> split0
-                                  (Left (x, False)) :< rest -> put false x >> get0 rest
-                                  (Left (_, True)) :< _ -> get2 Nothing Seq.empty q
-                                  (Right b) :< rest -> get2 (Just b) Seq.empty rest
-                      false' = mapSink (\(Left (x, _))-> x) false
-                      true' = mapSink (\(Left (x, _))-> x) true
-                      split0 = pourUntil (either snd (const True)) source' false'
-                               >>= maybe 
-                                      (return ()) 
-                                      (either (const $ split1 Nothing) (\b-> get source' >> split1 (Just b)))
-                      split1 mb = do (list, mx) <- getUntil (either (not . snd) (const True)) source'
-                                     let list' = Seq.fromList $ map (\(Left (x, True))-> x) list
-                                     maybe
-                                        (testEnd mb (Seq.fromList $ map (\(Left (x, True))-> x) list))
-                                        ((get source' >>) . get3 mb list' . Seq.singleton)
-                                        mx
-                      get2 mb q q' = case Seq.viewl q'
-                                     of Seq.EmptyL -> get source'
-                                                      >>= maybe (testEnd mb q) (get2 mb q . Seq.singleton)
-                                        (Left (x, True)) :< rest -> get2 mb (q |> x) rest
-                                        (Left (_, False)) :< _ -> get3 mb q q'
-                                        Right{} :< _ -> get3 mb q q'
-                      get3 mb q q' = do let list = mapMaybe 
-                                                      (either (Just . fst) (const Nothing)) 
-                                                      (Foldable.toList $ Seq.viewl q')
-                                        (q'', mn) <- pipe (\sink-> putList list sink >> get7 q' sink) (test mb q)
-                                        case mn of Nothing -> putQueue q false >> get0 q''
-                                                   Just 0 -> get0 q''
-                                                   Just n -> get8 (Just mb) n q''
-                      get7 q sink = do list <- getWhile (either (const True) (const False)) source'
-                                       rest <- putList (map (\(Left (x, _))-> x) list) sink
-                                       let q' = q >< Seq.fromList list
-                                       if null rest 
-                                          then get source' >>= maybe (return q') (\x-> get7 (q' |> x) sink)
-                                          else return q'
-                      testEnd mb q = do ((), n) <- pipe (const $ return ()) (test mb q)
-                                        case n of Nothing -> putQueue q false >> return ()
-                                                  _ -> return ()
-                      test mb q source'' = liftM snd $
-                                           pipe
-                                              (transduce (splitterToMarker s2) source'')
-                                              (\source'''-> let test0 (Left (_, False)) = get source''' 
-                                                                                          >> return Nothing
-                                                                test0 (Left (_, True)) = test1
-                                                                test0 (Right b') = maybe 
-                                                                                      (return ()) 
-                                                                                      (\b-> put edge (b, b')) 
-                                                                                      mb
-                                                                                   >> get source'''
-                                                                                   >> test1
-                                                                test1 = putQueue q true
-                                                                        >> getWhile (either snd (const False)) source'''
-                                                                        >>= \list-> putList list true'
-                                                                        >> get source'''
-                                                                        >> return (Just $ length list)
-                                                            in peek source''' >>= maybe (return Nothing) test0)
-                      get8 Nothing 0 q = get0 q
-                      get8 (Just mb) 0 q = get2 mb Seq.empty q
-                      get8 mmb n q = case Seq.viewl q 
-                                     of Left (_, False) :< rest -> get8 Nothing (pred n) rest
-                                        Left (_, True) :< rest -> get8 (maybe (Just Nothing) Just mmb) (pred n) rest
-                                        Right b :< rest -> get8 (Just (Just b)) n rest
-                                        EmptyL -> error "Expecting a non-empty queue!" 
-                 in split0)
-   >> return ()
+      (\source'->
+       let false' = markDown false
+           get0 q = case Seq.viewl q
+                    of Seq.EmptyL -> split0
+                       (x, False) :< rest -> putChunk false x >> get0 rest
+                       (_, True) :< _ -> get2 Seq.empty q
+           split0 = pourUntil (snd . head) source' false'
+                    >>= maybe
+                           (return ())
+                           (const $ split1) 
+           split1 = do (list, mx) <- getUntil (not . snd . head) source'
+                       let list' = Seq.fromList $ List.map (\(x, True)-> x) list
+                       maybe
+                          (testEnd (Seq.fromList $ List.map (\(x, True)-> x) list))
+                          ((getPrime source' >>) . get3 list' . Seq.singleton . head)
+                          mx
+           get2 q q' = case Seq.viewl q'
+                       of Seq.EmptyL -> get source'
+                                        >>= maybe (testEnd q) (get2 q . Seq.singleton)
+                          (x, True) :< rest -> get2 (q |> x) rest
+                          (_, False) :< _ -> get3 q q'
+           get3 q q' = do let list = mconcat $ List.map fst (Foldable.toList $ Seq.viewl q')
+                          (q'', mn) <- pipe (\sink-> putAll list sink >> get7 q' sink) (test q)
+                          case mn of Nothing -> putQueue q false >> get0 q''
+                                     Just 0 -> get0 q''
+                                     Just n -> get8 True n q''
+           get7 q sink = do list <- getWhile (const True . head) source'
+                            rest <- putAll (mconcat $ List.map (\(x, _)-> x) list) sink
+                            let q' = q >< Seq.fromList list
+                            if null rest
+                               then get source' >>= maybe (return q') (\x-> get7 (q' |> x) sink)
+                               else return q'
+           testEnd q = do ((), n) <- pipe (const $ return ()) (test q)
+                          case n of Nothing -> putQueue q false >> return ()
+                                    _ -> return ()
+           test q source'' = liftM snd $
+                             pipe
+                                (transduce (splitterToMarker s2) source'')
+                                (\source'''-> 
+                                  let test0 (x, False) = getPrime source'''
+                                                         >> if null x then try0 else return Nothing
+                                      test0 (_, True) = test1
+                                      test1 = do putQueue q true
+                                                 list <- getWhile (snd . head) source'''
+                                                 let chunk = mconcat (List.map fst list)
+                                                 putChunk true chunk
+                                                 getPrime source'''
+                                                 return (Just $ length chunk)
+                                      try0 = peek source''' >>= maybe (return Nothing) test0
+                                  in try0)
+           get8 False 0 q = get0 q
+           get8 True 0 q = get2 Seq.empty q
+           get8 _ n q | n > 0 =
+              case Seq.viewl q
+              of (x, False) :< rest | length x > n -> get0 ((drop n x, False) <| rest)
+                                    | otherwise -> get8 False (n - length x) rest
+                 (x, True) :< rest | length x > n -> get2 Seq.empty ((drop n x, True) <| rest)
+                                   | otherwise -> get8 True (n - length x) rest
+                 EmptyL -> error "Expecting a non-empty queue!"
+       in split0)
+      >> return ()
 
 -- | Combinator 'between' tracks the running balance of difference between the number of preceding starts of sections
 -- considered /true/ according to its first argument and the ones according to its second argument. The combinator
 -- passes to /true/ all input values for which the difference balance is positive. This combinator is typically used
 -- with 'startOf' and 'endOf' in order to count entire input sections and ignore their lengths.
-between :: forall m x b1 b2. Monad m => PairBinder m -> Splitter m x b1 -> Splitter m x b2 -> Splitter m x b1
-between binder s1 s2 = isolateSplitter $ \ source true false edge ->
-                         pipeG binder
-                            (transduce (splittersToPairMarker binder s1 s2) source)
-                            (let pass n x = (if n > 0 then put true x else put false x)
-                                            >> return n
-                                 pass' n x = (if n >= 0 then put true x else put false x)
-                                             >> return n
-                                 state n (Left (x, True, False)) = pass (succ n) x
-                                 state n (Left (x, False, True)) = pass' (pred n) x
-                                 state n (Left (x, True, True)) = pass' n x
-                                 state n (Left (x, False, False)) = pass n x
-                                 state 0 (Right (Left b)) = put edge b >> return 1
-                                 state n (Right (Left _)) = return (succ n)
-                                 state n (Right (Right _)) = return (pred n)
-                             in foldMStream_ state (0 :: Int))
-                         >> return ()
+between :: forall m x. (Monad m, FactorialMonoid x) => PairBinder m -> Splitter m x -> Splitter m x -> Splitter m x
+between binder s1 s2 = isolateSplitter $
+                       \ source true false ->
+                       pipeG binder
+                          (transduce (splittersToPairMarker binder s1 s2) source)
+                          (let pass n x = (if n > 0 then putChunk true x else putChunk false x)
+                                          >> return n
+                               pass' n x = (if n >= 0 then putChunk true x else putChunk false x)
+                                           >> return n
+                               state n (x, True, False) = pass (succ n) x
+                               state n (x, False, True) = pass' (pred n) x
+                               state n (x, True, True) = pass' n x
+                               state n (x, False, False) = pass n x
+                           in foldMStream_ state (0 :: Int))
+                          >> return ()
 
 -- Helper functions
 
 wrapMarkedSplitter ::
-   forall m x b1 b2. Monad m =>
-   Splitter m x b1
-   -> (forall a1 a2 a3 a4 d. (AncestorFunctor a1 d, AncestorFunctor a2 d, AncestorFunctor a3 d, AncestorFunctor a4 d) =>
-       Source m a1 (Either (x, Bool) b1) -> Sink m a2 x -> Sink m a3 x -> Sink m a4 b2 -> Coroutine d m ())
-   -> Splitter m x b2
-wrapMarkedSplitter splitter splitMarked = isolateSplitter $ \ source true false edge ->
+   forall m x. (Monad m, MonoidNull x) =>
+   Splitter m x
+   -> (forall a1 a2 a3 d. (AncestorFunctor a1 d, AncestorFunctor a2 d, AncestorFunctor a3 d,
+                           AncestorFunctor a1 (SinkFunctor d [(x, Bool)]),
+                           AncestorFunctor a2 (SourceFunctor d [(x, Bool)])) =>
+       Source m a1 [(x, Bool)] -> Sink m a2 x -> Sink m a3 x -> Coroutine d m ())
+   -> Splitter m x
+wrapMarkedSplitter splitter splitMarked = isolateSplitter $ 
+                                          \ source true false ->
                                           pipe
                                              (transduce (splitterToMarker splitter) source)
-                                             (\source'-> splitMarked source' true false edge)
+                                             (\source'-> splitMarked source' true false)
                                           >> return ()
 
-splitterToMarker :: forall m x b. Monad m => Splitter m x b -> Transducer m x (Either (x, Bool) b)
-splitterToMarker s = isolateTransducer $ \source sink->
-                     split s source
-                        (mapSink (\x-> Left (x, True)) sink)
-                        (mapSink (\x-> Left (x, False)) sink)
-                        (mapSink Right sink)
+splitterToMarker :: forall m x. (Monad m, MonoidNull x) => Splitter m x -> Transducer m x [(x, Bool)]
+splitterToMarker s = isolateTransducer mark
+   where mark :: forall d. Functor d => Source m d x -> Sink m d [(x, Bool)] -> Coroutine d m ()
+         mark source sink = split s source (markUpWith True sink) (markUpWith False sink)
 
-parserToSplitter :: forall m x b. Monad m => Parser m x b -> Splitter m x (Boundary b)
-parserToSplitter t = isolateSplitter $ \ source true false edge ->
+parserToSplitter :: forall m x b. (Monad m, Monoid x) => Parser m x b -> Splitter m x
+parserToSplitter t = isolateSplitter $ \ source true false ->
                      pipe
                         (transduce t source)
-                        (\source-> let true' = mapSink fromContent true
-                                       false' = mapSink fromContent false
-                                       topLevel = pourWhile isContent source false'
-                                                  >> get source 
-                                                  >>= maybe (return ()) (\x-> handleMarkup x >> topLevel)
-                                       handleMarkup (Markup p@Point{}) = put edge p >> return True
-                                       handleMarkup (Markup s@Start{}) = put edge s >> handleRegion >> return True
-                                       handleMarkup (Markup e@End{}) = put edge e >> return False
-                                       handleRegion = pourWhile isContent source true'
-                                                      >> get source
-                                                      >>= maybe (return ()) (\x -> handleMarkup x 
-                                                                                   >>= flip when handleRegion)
-                                   in topLevel)
+                        (\source-> 
+                          pipe (\true'->
+                                 pipe (\false'->
+                                        let topLevel = pourWhile isContent source false'
+                                                       >> get source 
+                                                       >>= maybe (return ()) (\x-> handleMarkup x >> topLevel)
+                                            handleMarkup (Markup p@Point{}) = putChunk true mempty >> return True
+                                            handleMarkup (Markup s@Start{}) = putChunk true mempty >> handleRegion >> return True
+                                            handleMarkup (Markup e@End{}) = putChunk false mempty >> return False
+                                            handleRegion = pourWhile isContent source true'
+                                                           >> get source
+                                                           >>= maybe (return ()) (\x -> handleMarkup x 
+                                                                                        >>= flip when handleRegion)
+                                        in topLevel)
+                                      (\src-> concatMapStream (\(Content x)-> x) src false))
+                               (\src-> concatMapStream (\(Content x)-> x) src true))
+                                                           
                         >> return ()
-   where isContent Markup{} = False
-         isContent Content{} = True
+   where isContent [Markup{}] = False
+         isContent [Content{}] = True
          fromContent (Content x) = x
 
-splittersToPairMarker :: forall m x b1 b2. Monad m => PairBinder m -> Splitter m x b1 -> Splitter m x b2 ->
-                         Transducer m x (Either (x, Bool, Bool) (Either b1 b2))
+splittersToPairMarker :: forall m x. (Monad m, FactorialMonoid x) => PairBinder m -> Splitter m x -> Splitter m x ->
+                         Transducer m x [(x, Bool, Bool)]
 splittersToPairMarker binder s1 s2 =
    let synchronizeMarks :: forall a1 a2 d. (AncestorFunctor a1 d, AncestorFunctor a2 d) =>
-                           Sink m a1 (Either (x, Bool, Bool) (Either b1 b2))
-                        -> Source m a2 (Either ((x, Bool), Bool) (Either b1 b2))
-                        -> Coroutine d m (Maybe (Seq (Either (x, Bool) (Either b1 b2)), Bool))
+                           Sink m a1 [(x, Bool, Bool)]
+                        -> Source m a2 [((x, Bool), Bool)]
+                        -> Coroutine d m (Maybe (Seq (x, Bool), Bool))
        synchronizeMarks sink source = foldMStream handleMark Nothing source where
-          handleMark Nothing (Right b) = put sink (Right b) >> return Nothing
-          handleMark Nothing (Left (p, head)) = return (Just (Seq.singleton (Left p), head))
-          handleMark (Just (q, head)) (Left (p, head')) | head == head' = return (Just (q |> Left p, head))
-          handleMark (Just (q, True)) (Right b@Left{}) = return (Just (q |> Right b, True))
-          handleMark (Just (q, False)) (Right b@Right{}) = return (Just (q |> Right b, False))
-          handleMark state (Right b) = put sink (Right b) >> return state
-          handleMark (Just (q, pos')) mark@(Left (p@(_, t), pos))
-             = case Seq.viewl q
-               of Seq.EmptyL -> return (Just (Seq.singleton (Left p), pos))
-                  Right b :< rest -> put sink (Right b)
-                                     >> handleMark (if Seq.null rest then Nothing else Just (rest, pos')) mark
-                  Left (y, t') :< rest -> put sink (Left $ if pos then (y, t, t') else (y, t', t))
-                                          >> return (if Seq.null rest then Nothing else Just (rest, pos'))
+          handleMark Nothing (p@(x, _), b) = return (Just (Seq.singleton p, b))
+          handleMark (Just (q, b)) mark@(p@(x, t), b')
+             | b == b' = return (Just (q |> p, b))
+             | otherwise = case Seq.viewl q
+                           of Seq.EmptyL -> handleMark Nothing mark
+                              (y, t') :< rest -> put sink (if b then (common, t', t) else (common, t, t'))
+                                                 >> if lx == ly
+                                                    then return (if Seq.null rest then Nothing else Just (rest, b))
+                                                    else if lx < ly 
+                                                         then return (Just ((leftover, t') <| rest, b))
+                                                         else handleMark (if Seq.null rest then Nothing 
+                                                                          else Just (rest, b)) 
+                                                                         ((leftover, t), b')
+                                 where lx = length x
+                                       ly = length y
+                                       (common, leftover) = if lx < ly then (x, drop lx y) else (y, drop ly x)
    in isolateTransducer $
       \source sink->
       pipe
          (\sync-> teeConsumers binder
-                     (\source1-> split s1 source1
-                                    (mapSink (\x-> Left ((x, True), True)) sync)
-                                    (mapSink (\x-> Left ((x, False), True)) sync)
-                                    (mapSink (Right. Left) sync))
-                     (\source2-> split s2 source2
-                                    (mapSink (\x-> Left ((x, True), False)) sync)
-                                    (mapSink (\x-> Left ((x, False), False)) sync)
-                                    (mapSink (Right . Right) sync))
+                     (\source1-> transduce (splitterToMarker s1) source1 (mapSink (\x-> (x, True)) sync))
+                     (\source2-> transduce (splitterToMarker s2) source2 (mapSink (\x-> (x, False)) sync))
                      source)
-          (synchronizeMarks sink)
+         (synchronizeMarks sink)
       >> return ()
 
-zipSplittersWith :: forall m x b1 b2 b. Monad m => 
-                    (Bool -> Bool -> Bool) -> 
-                    (forall a1 a2 d. (AncestorFunctor a1 d, AncestorFunctor a2 d) =>
-                     Source m a1 (Either b1 b2) -> Sink m a2 b -> Coroutine d m ()) -> 
-                    PairBinder m -> Splitter m x b1 -> Splitter m x b2 -> Splitter m x b
-zipSplittersWith f boundaries binder s1 s2
-   = isolateSplitter $ \ source true false edge ->
-     pipe
-        (\edge'->
-         pipeG binder
-            (transduce (splittersToPairMarker binder s1 s2) source)
-            (mapMStream_
-                (either
-                    (\(x, t1, t2)-> if f t1 t2 then put true x else put false x)
-                    (put edge'))))
-        (flip boundaries edge)
+zipSplittersWith :: forall m x. (Monad m, FactorialMonoid x) =>
+                    (Bool -> Bool -> Bool) -> PairBinder m -> Splitter m x -> Splitter m x -> Splitter m x
+zipSplittersWith f binder s1 s2
+   = isolateSplitter $ \ source true false ->
+     pipeG binder
+        (transduce (splittersToPairMarker binder s1 s2) source)
+        (mapMStream_ (\[(x, t1, t2)]-> if f t1 t2 then putChunk true x else putChunk false x))
      >> return ()
 
 -- | Runs the second argument on every contiguous region of input source (typically produced by 'splitterToMarker')
 -- whose all values either match @Left (_, True)@ or @Left (_, False)@.
-groupMarks :: (Monad m, AncestorFunctor a d, AncestorFunctor a (SinkFunctor d x)) =>
-              Source m a (Either (x, Bool) b) ->
-              (Maybe (Maybe b) -> Source m (SourceFunctor d x) x -> Coroutine (SourceFunctor d x) m r) ->
+groupMarks :: (Monad m, MonoidNull x, AncestorFunctor a d, AncestorFunctor a (SinkFunctor d x), 
+               AncestorFunctor a (SinkFunctor (SinkFunctor d x) [(x, Bool)])) =>
+              Source m a [(x, Bool)] ->
+              (Bool -> Source m (SourceFunctor d x) x -> Coroutine (SourceFunctor d x) m r) ->
               Coroutine d m ()
 groupMarks source getConsumer = peek source >>= loop
-   where loop = maybe (return ()) ((>>= loop . fst) . either startContent startRegion)
-         startContent (_, False) = pipe (next False) (getConsumer Nothing)
-         startContent (_, True) = pipe (next True) (getConsumer $ Just Nothing)
-         startRegion b = get source >> pipe (next True) (getConsumer (Just $ Just b))
-         next t sink = pourUntil (either (\(_, t')-> t /= t') (const True)) source (mapSink (\(Left (x, _))-> x) sink)
+   where loop = maybe (return ()) ((>>= loop . fst) . startContent)
+         startContent (_, False) = pipe (next False) (getConsumer False)
+         startContent (_, True) = pipe (next True) (getConsumer True)
+         next t sink = liftM (fmap head) $
+                       pourUntil ((\(_, t')-> t /= t') . head) source (markDown sink)
 
-splitInput :: forall m a1 a2 a3 d x b. (Monad m, AncestorFunctor a1 d, AncestorFunctor a2 d, AncestorFunctor a3 d) =>
-              Splitter m x b -> Source m a1 x -> Sink m a2 x -> Sink m a3 x -> Coroutine d m ()
-splitInput splitter source true false = split splitter source true false (nullSink :: Sink m d b)
+splitInput :: forall m a1 a2 a3 d x. (Monad m, Monoid x, 
+                                      AncestorFunctor a1 d, AncestorFunctor a2 d, AncestorFunctor a3 d) =>
+              Splitter m x -> Source m a1 x -> Sink m a2 x -> Sink m a3 x -> Coroutine d m ()
+splitInput splitter source true false = split splitter source true false
 
-findsTrueIn :: forall m a d x b. (Monad m, AncestorFunctor a d)
-               => Splitter m x b -> Source m a x -> Coroutine d m (Maybe (Maybe b))
+findsTrueIn :: forall m a d x. (Monad m, MonoidNull x, AncestorFunctor a d)
+               => Splitter m x -> Source m a x -> Coroutine d m Bool
 findsTrueIn splitter source = pipe
-                                 (\testTrue-> pipe
-                                                 (split splitter (liftSource source :: Source m d x)
-                                                     testTrue
-                                                     (nullSink :: Sink m d x))
-                                                 get)
-                                 get
-                              >>= \(((), maybeEdge), maybeTrue)-> return $
-                                                                  case maybeEdge
-                                                                  of Nothing -> fmap (const Nothing) maybeTrue
-                                                                     _ -> Just maybeEdge
+                                 (\testTrue-> split splitter (liftSource source :: Source m d x)
+                                                 testTrue
+                                                 (nullSink :: Sink m d x))
+                                 (getRead readEof)
+                              >>= \((), eof)-> return $ not eof
 
-findsFalseIn :: forall m a d x b. (Monad m, AncestorFunctor a d) => Splitter m x b -> Source m a x -> Coroutine d m Bool
+findsFalseIn :: forall m a d x. (Monad m, MonoidNull x, AncestorFunctor a d) =>
+                Splitter m x -> Source m a x -> Coroutine d m Bool
 findsFalseIn splitter source = pipe
                                   (\testFalse-> split splitter (liftSource source :: Source m d x)
                                                    (nullSink :: Sink m d x)
-                                                   testFalse
-                                                   (nullSink :: Sink m d b))
-                                  get
-                               >>= \((), maybeFalse)-> return (isJust maybeFalse)
+                                                   testFalse)
+                                  (getRead readEof)
+                               >>= \((), eof)-> return $ not eof
 
+readEof :: forall x. MonoidNull x => Reader x (Bool -> Bool) Bool
+readEof x | null x = Deferred readEof True
+          | otherwise = Final x False
+
 teeConsumers :: forall m a d x r1 r2. Monad m => 
                 PairBinder m 
                 -> (forall a'. OpenConsumer m a' (SourceFunctor (SinkFunctor d x) x) x r1)
@@ -930,17 +818,21 @@
 
 -- | Given a 'Splitter', a 'Source', and two consumer functions, 'splitInputToConsumers' runs the splitter on the source
 -- and feeds the splitter's /true/ and /false/ outputs, respectively, to the two consumers.
-splitInputToConsumers :: forall m a d d1 x b. (Monad m, d1 ~ SinkFunctor d x, AncestorFunctor a d) =>
-                         PairBinder m -> Splitter m x b -> Source m a x ->
+splitInputToConsumers :: forall m a d d1 x. (Monad m, Monoid x, d1 ~ SinkFunctor d x, AncestorFunctor a d) =>
+                         PairBinder m -> Splitter m x -> Source m a x ->
                          (Source m (SourceFunctor d1 x) x -> Coroutine (SourceFunctor d1 x) m ()) ->
                          (Source m (SourceFunctor d x) x -> Coroutine (SourceFunctor d x) m ()) ->
                          Coroutine d m ()
 splitInputToConsumers binder s source trueConsumer falseConsumer
    = pipeG binder
         (\false-> pipeG binder
-                     (\true-> split s source' true false (nullSink :: Sink m d b))
+                     (\true-> split s source' true false)
                      trueConsumer)
         falseConsumer
      >> return ()
    where source' :: Source m d x
          source' = liftSource source
+
+-- | Like 'putAll', except it puts the contents of the given 'Data.Sequence.Seq' into the sink.
+putQueue :: forall m a d x. (Monad m, MonoidNull x, AncestorFunctor a d) => Seq x -> Sink m a x -> Coroutine d m x
+putQueue q sink = putAll (mconcat $ Foldable.toList $ Seq.viewl q) sink
diff --git a/Control/Concurrent/SCC/Combinators/Parallel.hs b/Control/Concurrent/SCC/Combinators/Parallel.hs
--- a/Control/Concurrent/SCC/Combinators/Parallel.hs
+++ b/Control/Concurrent/SCC/Combinators/Parallel.hs
@@ -22,7 +22,7 @@
 module Control.Concurrent.SCC.Combinators.Parallel (
    -- * Consumer, producer, and transducer combinators
    Combinators.consumeBy, Combinators.prepend, Combinators.append, Combinators.substitute,
-   Combinators.PipeableComponentPair, (>->), Combinators.JoinableComponentPair (Combinators.sequence), join,
+   PipeableComponentPair, (>->), Combinators.JoinableComponentPair (Combinators.sequence), join,
    -- * Splitter combinators
    Combinators.sNot,
    -- ** Pseudo-logic flow combinators
@@ -64,15 +64,19 @@
    -- ** positional splitters
    Combinators.startOf, Combinators.endOf, (...),
    -- * Parser support
-   Combinators.splitterToMarker, Combinators.parseRegions, Combinators.parseNestedRegions, parseEachNestedRegion,
+   Combinators.splitterToMarker, Combinators.parseRegions,
    )
 where
 
 import Prelude hiding ((&&), (||), even, last, sequence)
+import Data.Monoid (Monoid)
 import Data.Text (Text)
 
 import Control.Monad.Parallel (MonadParallel)
 import Control.Monad.Coroutine (parallelBinder)
+import Data.Monoid.Null (MonoidNull)
+import Data.Monoid.Factorial (FactorialMonoid)
+
 import Control.Concurrent.SCC.Types
 import Control.Concurrent.SCC.Coercions (Coercible)
 import qualified Control.Concurrent.SCC.Combinators as Combinators
@@ -86,8 +90,8 @@
 --    * The output produced by the first child component is consumed by the second child component.
 --
 --    * The result output, if any, is the output of the second component.
-(>->) :: (MonadParallel m, Combinators.PipeableComponentPair m w c1 c2 c3) => c1 -> c2 -> c3
-(>->) = Combinators.compose parallelBinder
+(>->) :: (MonadParallel m, PipeableComponentPair m w c1 c2 c3) => c1 -> c2 -> c3
+(>->) = compose parallelBinder
 
 -- | The 'join' combinator may apply the components in any order.
 join :: (MonadParallel m, Combinators.JoinableComponentPair t1 t2 t3 m x y c1 c2 c3) => c1 -> c2 -> c3
@@ -96,38 +100,34 @@
 -- | The '>&' combinator sends the /true/ sink output of its left operand to the input of its right operand for further
 -- splitting. Both operands' /false/ sinks are connected to the /false/ sink of the combined splitter, but any input
 -- value to reach the /true/ sink of the combined component data must be deemed true by both splitters.
-(>&) :: forall m x b1 b2. MonadParallel m => Splitter m x b1 -> Splitter m x b2 -> Splitter m x (b1, b2)
+(>&) :: (MonadParallel m, Monoid x) => Splitter m x -> Splitter m x -> Splitter m x
 (>&) = Combinators.sAnd parallelBinder
 
 -- | A '>|' combinator's input value can reach its /false/ sink only by going through both argument splitters' /false/
 -- sinks.
-(>|) :: forall m x b1 b2. MonadParallel m => Splitter m x b1 -> Splitter m x b2 -> Splitter m x (Either b1 b2) 
+(>|) :: (MonadParallel m, Monoid x) => Splitter m x -> Splitter m x -> Splitter m x 
 (>|) =  Combinators.sOr parallelBinder
 
 -- | Combinator '&&' is a pairwise logical conjunction of two splitters run in parallel on the same input.
-(&&) :: forall m x b1 b2. MonadParallel m => Splitter m x b1 -> Splitter m x b2 -> Splitter m x (b1, b2)
+(&&) :: (MonadParallel m, FactorialMonoid x) => Splitter m x -> Splitter m x -> Splitter m x
 (&&) = Combinators.pAnd parallelBinder
 
 -- | Combinator '||' is a pairwise logical disjunction of two splitters run in parallel on the same input.
-(||) :: forall m x b1 b2. MonadParallel m => Splitter m x b1 -> Splitter m x b2 -> Splitter m x (Either b1 b2)
+(||) :: (MonadParallel m, FactorialMonoid x) => Splitter m x -> Splitter m x -> Splitter m x
 (||) = Combinators.pOr parallelBinder
 
-ifs :: (MonadParallel m, Branching c m x ()) => Splitter m x b -> c -> c -> c
+ifs :: (MonadParallel m, Monoid x, Branching c m x ()) => Splitter m x -> c -> c -> c
 ifs = Combinators.ifs parallelBinder
 
-wherever :: MonadParallel m => Transducer m x x -> Splitter m x b -> Transducer m x x
+wherever :: (MonadParallel m, Monoid x) => Transducer m x x -> Splitter m x -> Transducer m x x
 wherever = Combinators.wherever parallelBinder
 
-unless :: MonadParallel m => Transducer m x x -> Splitter m x b -> Transducer m x x
+unless :: (MonadParallel m, Monoid x) => Transducer m x x -> Splitter m x -> Transducer m x x
 unless = Combinators.unless parallelBinder
 
--- | Converts a boundary-marking splitter into a parser.
-parseEachNestedRegion :: MonadParallel m => Splitter m x (Boundary b) -> Transducer m x y -> Transducer m x (Markup b y)
-parseEachNestedRegion = Combinators.parseEachNestedRegion parallelBinder
-
 -- | The recursive combinator 'while' feeds the true sink of the argument splitter back to itself, modified by the
 -- argument transducer. Data fed to the splitter's false sink is passed on unmodified.
-while :: MonadParallel m => Transducer m x x -> Splitter m x b -> Transducer m x x
+while :: (MonadParallel m, MonoidNull x) => Transducer m x x -> Splitter m x -> Transducer m x x
 while t s = Combinators.while parallelBinder t s (while t s)
 
 -- | The recursive combinator 'nestedIn' combines two splitters into a mutually recursive loop acting as a single
@@ -136,7 +136,7 @@
 -- hierarchically structured streams. If we gave it some input containing a flat sequence of values, and assuming both
 -- component splitters are deterministic and stateless, an input value would either not loop at all or it would loop
 -- forever.
-nestedIn :: MonadParallel m => Splitter m x b -> Splitter m x b -> Splitter m x b
+nestedIn :: (MonadParallel m, MonoidNull x) => Splitter m x -> Splitter m x -> Splitter m x
 nestedIn s1 s2 = Combinators.nestedIn parallelBinder s1 s2 (nestedIn s1 s2)
 
 -- | The 'foreach' combinator is similar to the combinator 'ifs' in that it combines a splitter and two transducers into
@@ -144,7 +144,7 @@
 -- input as the splitter chunks it up. Each contiguous portion of the input that the splitter sends to one of its two
 -- sinks gets transducered through the appropriate argument transducer as that transducer's whole input. As soon as the
 -- contiguous portion is finished, the transducer gets terminated.
-foreach :: (MonadParallel m, Branching c m x ()) => Splitter m x b -> c -> c -> c
+foreach :: (MonadParallel m, MonoidNull x, Branching c m x ()) => Splitter m x -> c -> c -> c
 foreach = Combinators.foreach parallelBinder
 
 -- | The 'having' combinator combines two pure splitters into a pure splitter. One splitter is used to chunk the input
@@ -152,24 +152,25 @@
 -- second splitter is instantiated and run on each portion of the input that goes to first splitter's /true/ sink. If
 -- the second splitter sends any output at all to its /true/ sink, the whole input portion is passed on to the /true/
 -- sink of the combined splitter, otherwise it goes to its /false/ sink.
-having :: (MonadParallel m, Coercible x y) => Splitter m x b1 -> Splitter m y b2 -> Splitter m x b1
+having :: (MonadParallel m, MonoidNull x, MonoidNull y, Coercible x y) => Splitter m x -> Splitter m y -> Splitter m x
 having = Combinators.having parallelBinder
 
 -- | The 'havingOnly' combinator is analogous to the 'having' combinator, but it succeeds and passes each chunk of the
 -- input to its /true/ sink only if the second splitter sends no part of it to its /false/ sink.
-havingOnly :: (MonadParallel m, Coercible x y) => Splitter m x b1 -> Splitter m y b2 -> Splitter m x b1
+havingOnly :: (MonadParallel m, MonoidNull x, MonoidNull y, Coercible x y) => 
+              Splitter m x -> Splitter m y -> Splitter m x
 havingOnly = Combinators.havingOnly parallelBinder
 
 -- | Combinator 'followedBy' treats its argument 'Splitter's as patterns components and returns a 'Splitter' that
 -- matches their concatenation. A section of input is considered /true/ by the result iff its prefix is considered
 -- /true/ by argument /s1/ and the rest of the section is considered /true/ by /s2/. The splitter /s2/ is started anew
 -- after every section split to /true/ sink by /s1/.
-followedBy :: MonadParallel m => Splitter m x b1 -> Splitter m x b2 -> Splitter m x (b1, b2)
+followedBy :: (MonadParallel m, FactorialMonoid x) => Splitter m x -> Splitter m x -> Splitter m x
 followedBy = Combinators.followedBy parallelBinder
 
 -- | Combinator '...' tracks the running balance of difference between the number of preceding starts of sections
 -- considered /true/ according to its first argument and the ones according to its second argument. The combinator
 -- passes to /true/ all input values for which the difference balance is positive. This combinator is typically used
 -- with 'startOf' and 'endOf' in order to count entire input sections and ignore their lengths.
-(...) :: MonadParallel m => Splitter m x b1 -> Splitter m x b2 -> Splitter m x b1
+(...) :: (MonadParallel m, FactorialMonoid x) => Splitter m x -> Splitter m x -> Splitter m x
 (...) = Combinators.between parallelBinder
diff --git a/Control/Concurrent/SCC/Combinators/Sequential.hs b/Control/Concurrent/SCC/Combinators/Sequential.hs
--- a/Control/Concurrent/SCC/Combinators/Sequential.hs
+++ b/Control/Concurrent/SCC/Combinators/Sequential.hs
@@ -22,7 +22,7 @@
 module Control.Concurrent.SCC.Combinators.Sequential (
    -- * Consumer, producer, and transducer combinators
    Combinators.consumeBy, Combinators.prepend, Combinators.append, Combinators.substitute,
-   Combinators.PipeableComponentPair, (>->), Combinators.JoinableComponentPair (Combinators.sequence), join,
+   PipeableComponentPair, (>->), Combinators.JoinableComponentPair (Combinators.sequence), join,
    -- * Splitter combinators
    Combinators.sNot,
    -- ** Pseudo-logic flow combinators
@@ -64,14 +64,18 @@
    -- ** positional splitters
    Combinators.startOf, Combinators.endOf, (...),
    -- * Parser support
-   Combinators.splitterToMarker, Combinators.parseRegions, Combinators.parseNestedRegions, parseEachNestedRegion,
+   Combinators.splitterToMarker, Combinators.parseRegions,
    )
 where
 
 import Prelude hiding ((&&), (||), even, last, sequence)
+import Data.Monoid (Monoid)
 import Data.Text (Text)
 
 import Control.Monad.Coroutine (sequentialBinder)
+import Data.Monoid.Null (MonoidNull)
+import Data.Monoid.Factorial (FactorialMonoid)
+
 import Control.Concurrent.SCC.Types
 import Control.Concurrent.SCC.Coercions (Coercible)
 import qualified Control.Concurrent.SCC.Combinators as Combinators
@@ -85,8 +89,8 @@
 --    * The output produced by the first child component is consumed by the second child component.
 --
 --    * The result output, if any, is the output of the second component.
-(>->) :: (Monad m, Combinators.PipeableComponentPair m w c1 c2 c3) => c1 -> c2 -> c3
-(>->) = Combinators.compose sequentialBinder
+(>->) :: (Monad m, PipeableComponentPair m w c1 c2 c3) => c1 -> c2 -> c3
+(>->) = compose sequentialBinder
 
 -- | The 'join' combinator may apply the components in any order.
 join :: (Monad m, Combinators.JoinableComponentPair t1 t2 t3 m x y c1 c2 c3) => c1 -> c2 -> c3
@@ -95,38 +99,34 @@
 -- | The '>&' combinator sends the /true/ sink output of its left operand to the input of its right operand for further
 -- splitting. Both operands' /false/ sinks are connected to the /false/ sink of the combined splitter, but any input
 -- value to reach the /true/ sink of the combined component data must be deemed true by both splitters.
-(>&) :: Monad m => Splitter m x b1 -> Splitter m x b2 -> Splitter m x (b1, b2)
+(>&) :: (Monad m, Monoid x) => Splitter m x -> Splitter m x -> Splitter m x
 (>&) = Combinators.sAnd sequentialBinder
 
 -- | A '>|' combinator's input value can reach its /false/ sink only by going through both argument splitters' /false/
 -- sinks.
-(>|) :: Monad m => Splitter m x b1 -> Splitter m x b2 -> Splitter m x (Either b1 b2) 
+(>|) :: (Monad m, Monoid x) => Splitter m x -> Splitter m x -> Splitter m x 
 (>|) =  Combinators.sOr sequentialBinder
 
 -- | Combinator '&&' is a pairwise logical conjunction of two splitters run in parallel on the same input.
-(&&) :: Monad m => Splitter m x b1 -> Splitter m x b2 -> Splitter m x (b1, b2)
+(&&) :: (Monad m, FactorialMonoid x) => Splitter m x -> Splitter m x -> Splitter m x
 (&&) = Combinators.pAnd sequentialBinder
 
 -- | Combinator '||' is a pairwise logical disjunction of two splitters run in parallel on the same input.
-(||) :: Monad m => Splitter m x b1 -> Splitter m x b2 -> Splitter m x (Either b1 b2)
+(||) :: (Monad m, FactorialMonoid x) => Splitter m x -> Splitter m x -> Splitter m x
 (||) = Combinators.pOr sequentialBinder
 
-ifs :: (Monad m, Branching c m x ()) => Splitter m x b -> c -> c -> c
+ifs :: (Monad m, Monoid x, Branching c m x ()) => Splitter m x -> c -> c -> c
 ifs = Combinators.ifs sequentialBinder
 
-wherever :: Monad m => Transducer m x x -> Splitter m x b -> Transducer m x x
+wherever :: (Monad m, Monoid x) => Transducer m x x -> Splitter m x -> Transducer m x x
 wherever = Combinators.wherever sequentialBinder
 
-unless :: Monad m => Transducer m x x -> Splitter m x b -> Transducer m x x
+unless :: (Monad m, Monoid x) => Transducer m x x -> Splitter m x -> Transducer m x x
 unless = Combinators.unless sequentialBinder
 
--- | Converts a boundary-marking splitter into a parser.
-parseEachNestedRegion :: Monad m => Splitter m x (Boundary b) -> Transducer m x y -> Transducer m x (Markup b y)
-parseEachNestedRegion = Combinators.parseEachNestedRegion sequentialBinder
-
 -- | The recursive combinator 'while' feeds the true sink of the argument splitter back to itself, modified by the
 -- argument transducer. Data fed to the splitter's false sink is passed on unmodified.
-while :: Monad m => Transducer m x x -> Splitter m x b -> Transducer m x x
+while :: (Monad m, MonoidNull x) => Transducer m x x -> Splitter m x -> Transducer m x x
 while t s = Combinators.while sequentialBinder t s (while t s)
 
 -- | The recursive combinator 'nestedIn' combines two splitters into a mutually recursive loop acting as a single
@@ -135,7 +135,7 @@
 -- hierarchically structured streams. If we gave it some input containing a flat sequence of values, and assuming both
 -- component splitters are deterministic and stateless, an input value would either not loop at all or it would loop
 -- forever.
-nestedIn :: Monad m => Splitter m x b -> Splitter m x b -> Splitter m x b
+nestedIn :: (Monad m, MonoidNull x) => Splitter m x -> Splitter m x -> Splitter m x
 nestedIn s1 s2 = Combinators.nestedIn sequentialBinder s1 s2 (nestedIn s1 s2)
 
 -- | The 'foreach' combinator is similar to the combinator 'ifs' in that it combines a splitter and two transducers into
@@ -143,7 +143,7 @@
 -- input as the splitter chunks it up. Each contiguous portion of the input that the splitter sends to one of its two
 -- sinks gets transducered through the appropriate argument transducer as that transducer's whole input. As soon as the
 -- contiguous portion is finished, the transducer gets terminated.
-foreach :: (Monad m, Branching c m x ()) => Splitter m x b -> c -> c -> c
+foreach :: (Monad m, MonoidNull x, Branching c m x ()) => Splitter m x -> c -> c -> c
 foreach = Combinators.foreach sequentialBinder
 
 -- | The 'having' combinator combines two pure splitters into a pure splitter. One splitter is used to chunk the input
@@ -151,24 +151,24 @@
 -- second splitter is instantiated and run on each portion of the input that goes to first splitter's /true/ sink. If
 -- the second splitter sends any output at all to its /true/ sink, the whole input portion is passed on to the /true/
 -- sink of the combined splitter, otherwise it goes to its /false/ sink.
-having :: (Monad m, Coercible x y) => Splitter m x b1 -> Splitter m y b2 -> Splitter m x b1
+having :: (Monad m, MonoidNull x, MonoidNull y, Coercible x y) => Splitter m x -> Splitter m y -> Splitter m x
 having = Combinators.having sequentialBinder
 
 -- | The 'havingOnly' combinator is analogous to the 'having' combinator, but it succeeds and passes each chunk of the
 -- input to its /true/ sink only if the second splitter sends no part of it to its /false/ sink.
-havingOnly :: (Monad m, Coercible x y) => Splitter m x b1 -> Splitter m y b2 -> Splitter m x b1
+havingOnly :: (Monad m, MonoidNull x, MonoidNull y, Coercible x y) => Splitter m x -> Splitter m y -> Splitter m x
 havingOnly = Combinators.havingOnly sequentialBinder
 
 -- | Combinator 'followedBy' treats its argument 'Splitter's as patterns components and returns a 'Splitter' that
 -- matches their concatenation. A section of input is considered /true/ by the result iff its prefix is considered
 -- /true/ by argument /s1/ and the rest of the section is considered /true/ by /s2/. The splitter /s2/ is started anew
 -- after every section split to /true/ sink by /s1/.
-followedBy :: Monad m => Splitter m x b1 -> Splitter m x b2 -> Splitter m x (b1, b2)
+followedBy :: (Monad m, FactorialMonoid x) => Splitter m x -> Splitter m x -> Splitter m x
 followedBy = Combinators.followedBy sequentialBinder
 
 -- | Combinator '...' tracks the running balance of difference between the number of preceding starts of sections
 -- considered /true/ according to its first argument and the ones according to its second argument. The combinator
 -- passes to /true/ all input values for which the difference balance is positive. This combinator is typically used
 -- with 'startOf' and 'endOf' in order to count entire input sections and ignore their lengths.
-(...) :: Monad m => Splitter m x b1 -> Splitter m x b2 -> Splitter m x b1
+(...) :: (Monad m, FactorialMonoid x) => Splitter m x -> Splitter m x -> Splitter m x
 (...) = Combinators.between sequentialBinder
diff --git a/Control/Concurrent/SCC/Configurable.hs b/Control/Concurrent/SCC/Configurable.hs
--- a/Control/Concurrent/SCC/Configurable.hs
+++ b/Control/Concurrent/SCC/Configurable.hs
@@ -1,5 +1,5 @@
 {- 
-    Copyright 2008-2010 Mario Blazevic
+    Copyright 2008-2013 Mario Blazevic
 
     This file is part of the Streaming Component Combinators (SCC) project.
 
@@ -18,14 +18,14 @@
              MultiParamTypeClasses, FlexibleContexts, FlexibleInstances, FunctionalDependencies, TypeFamilies #-}
 {-# OPTIONS_HADDOCK prune #-}
 
--- | The "Components" module defines thin wrappers around the 'Transducer' and 'Splitter' primitives and combinators,
--- relying on the "Control.Concurrent.SCC.ComponentTypes" module.
+-- | This module exports the entire SCC library except for low-level modules "Control.Concurrent.SCC.Streams" and
+-- "Control.Concurrent.SCC.Types". The exported combinators can be configured to run their components sequentially or in
+-- parallel depending on the available resources.
 
 module Control.Concurrent.SCC.Configurable 
        (
-          module Control.Concurrent.SCC.Streams,
-          module Control.Concurrent.SCC.Types,
           module Control.Concurrent.SCC.Configurable,
+          module Control.Concurrent.Configuration,
           XML.XMLToken(..), XML.expandXMLEntity
        )
 where
@@ -33,10 +33,14 @@
 import Prelude hiding (appendFile, even, id, last, sequence, (||), (&&))
 import qualified Control.Category
 import Data.Text (Text)
+import Data.Monoid (Monoid, Sum)
 import System.IO (Handle)
 
 import Control.Monad.Coroutine
 import Control.Monad.Parallel (MonadParallel(..))
+import Data.Monoid.Null (MonoidNull)
+import Data.Monoid.Factorial (FactorialMonoid)
+import Data.Monoid.Cancellative (LeftCancellativeMonoid)
 
 import Control.Concurrent.SCC.Streams
 import Control.Concurrent.SCC.Types
@@ -47,7 +51,7 @@
 import qualified Control.Concurrent.SCC.XML as XML
 import Control.Concurrent.SCC.Primitives (OccurenceTag)
 import Control.Concurrent.SCC.XML (XMLToken)
-import Control.Concurrent.Configuration (Component, atomic, lift, liftSequentialPair)
+import Control.Concurrent.Configuration (Component, atomic)
 import qualified Control.Concurrent.Configuration as Configuration
 
 -- * Configurable component types
@@ -70,7 +74,7 @@
 -- should distribute only the original input data, and feed it into the sinks in the same order it has been read from
 -- the source. If the two 'Sink c x' arguments of a splitter are the same, the splitter must act as an identity
 -- transform.
-type SplitterComponent m x b = Component (Splitter m x b)
+type SplitterComponent m x = Component (Splitter m x)
 
 -- | The constant cost of each I/O-performing component.
 ioCost :: Int
@@ -83,191 +87,192 @@
 coerce = atomic "coerce" 1 Coercion.coerce
 
 -- | Adjusts the argument consumer to consume the stream of a data type coercible to the type it was meant to consume.
-adaptConsumer :: (Monad m, Coercible x y) => ConsumerComponent m y r -> ConsumerComponent m x r
-adaptConsumer = lift 1 "adaptConsumer" Coercion.adaptConsumer
+adaptConsumer :: (Monad m, Monoid x, Monoid y, Coercible x y) => ConsumerComponent m y r -> ConsumerComponent m x r
+adaptConsumer = Configuration.lift 1 "adaptConsumer" Coercion.adaptConsumer
 
 -- | Adjusts the argument producer to produce the stream of a data type coercible from the type it was meant to produce.
-adaptProducer :: (Monad m, Coercible x y) => ProducerComponent m x r -> ProducerComponent m y r
-adaptProducer = lift 1 "adaptProducer" Coercion.adaptProducer
+adaptProducer :: (Monad m, Monoid x, Monoid y, Coercible x y) => ProducerComponent m x r -> ProducerComponent m y r
+adaptProducer = Configuration.lift 1 "adaptProducer" Coercion.adaptProducer
 
 -- * Splitter isomorphism
 
 -- | Adjusts the argument splitter to split the stream of a data type isomorphic to the type it was meant to split.
-adaptSplitter :: (Monad m, Coercible x y, Coercible y x) => SplitterComponent m x b -> SplitterComponent m y b
-adaptSplitter = lift 1 "adaptSplitter" Coercion.adaptSplitter
+adaptSplitter :: (Monad m, Monoid x, Monoid y, Coercible x y, Coercible y x) => 
+                 SplitterComponent m x -> SplitterComponent m y
+adaptSplitter = Configuration.lift 1 "adaptSplitter" Coercion.adaptSplitter
 
 -- * I/O components
 -- ** I/O producers
 
 -- | ProducerComponent 'fromStdIn' feeds the given sink from the standard input.
-fromStdIn :: ProducerComponent IO Char ()
+fromStdIn :: ProducerComponent IO Text ()
 fromStdIn = atomic "fromStdIn" ioCost Primitive.fromStdIn
 
 -- | ProducerComponent 'fromFile' opens the named file and feeds the given sink from its contents.
-fromFile :: String -> ProducerComponent IO Char ()
+fromFile :: String -> ProducerComponent IO Text ()
 fromFile path = atomic "fromFile" ioCost (Primitive.fromFile path)
 
 -- | ProducerComponent 'fromHandle' feeds the given sink from the open file /handle/.
-fromHandle :: Handle -> ProducerComponent IO Char ()
+fromHandle :: Handle -> ProducerComponent IO Text ()
 fromHandle handle = atomic "fromHandle" ioCost (Primitive.fromHandle handle)
 
 -- ** I/O consumers
 
 -- | ConsumerComponent 'toStdOut' copies the given source into the standard output.
-toStdOut :: ConsumerComponent IO Char ()
+toStdOut :: ConsumerComponent IO Text ()
 toStdOut = atomic "toStdOut" ioCost Primitive.toStdOut
 
 -- | ConsumerComponent 'toFile' opens the named file and copies the given source into it.
-toFile :: String -> ConsumerComponent IO Char ()
+toFile :: String -> ConsumerComponent IO Text ()
 toFile path = atomic "toFile" ioCost (Primitive.toFile path)
 
 -- | ConsumerComponent 'appendFile' opens the name file and appends the given source to it.
-appendFile :: String -> ConsumerComponent IO Char ()
+appendFile :: String -> ConsumerComponent IO Text ()
 appendFile path = atomic "appendFile" ioCost (Primitive.appendFile path)
 
 -- | ConsumerComponent 'toHandle' copies the given source into the open file /handle/.
-toHandle :: Handle -> ConsumerComponent IO Char ()
+toHandle :: Handle -> ConsumerComponent IO Text ()
 toHandle handle = atomic "toHandle" ioCost (Primitive.toHandle handle)
 
 -- * Generic components
 
--- | 'fromList' produces the contents of the given list argument.
-fromList :: Monad m => [x] -> ProducerComponent m x ()
-fromList l = atomic "fromList" 1 (Primitive.fromList l)
+-- | 'produceFrom' produces the contents of the given argument.
+produceFrom :: (Monad m, MonoidNull x) => x -> ProducerComponent m x ()
+produceFrom l = atomic "produceFrom" 1 (Primitive.produceFrom l)
    
 -- ** Generic consumers
 
--- | ConsumerComponent 'toList' copies the given source into a list.
-toList :: Monad m => ConsumerComponent m x [x]
-toList = atomic "toList" 1 Primitive.toList
+-- | ConsumerComponent 'consumeInto' collects the given source into the return value.
+consumeInto :: (Monad m, Monoid x) => ConsumerComponent m x x
+consumeInto = atomic "consumeInto" 1 Primitive.consumeInto
 
 -- | The 'suppress' consumer suppresses all input it receives. It is equivalent to 'substitute' []
 suppress :: Monad m => ConsumerComponent m x ()
 suppress = atomic "suppress" 1 Primitive.suppress
 
 -- | The 'erroneous' consumer reports an error if any input reaches it.
-erroneous :: Monad m => String -> ConsumerComponent m x ()
+erroneous :: (Monad m, MonoidNull x) => String -> ConsumerComponent m x ()
 erroneous message = atomic "erroneous" 0 (Primitive.erroneous message)
 
 -- ** Generic transducers
 
 -- | TransducerComponent 'id' passes its input through unmodified.
-id :: Monad m => TransducerComponent m x x
-id = atomic "id" 1 Control.Category.id
+id :: (Monad m, Monoid x) => TransducerComponent m x x
+id = atomic "id" 1 $ Transducer pour_
 
 -- | TransducerComponent 'unparse' removes all markup from its input and passes the content through.
-unparse :: Monad m => TransducerComponent m (Markup b x) x
+unparse :: (Monad m, Monoid x) => TransducerComponent m [Markup b x] x
 unparse = atomic "unparse" 1 Primitive.unparse
 
 -- | TransducerComponent 'parse' prepares input content for subsequent parsing.
-parse :: Monad m => TransducerComponent m x (Markup y x)
+parse :: (Monad m, Monoid x) => ParserComponent m x y
 parse = atomic "parse" 1 Primitive.parse
 
 -- | The 'lowercase' transforms all uppercase letters in the input to lowercase, leaving the rest unchanged.
-lowercase :: Monad m => TransducerComponent m Char Char
+lowercase :: Monad m => TransducerComponent m String String
 lowercase = atomic "lowercase" 1 Primitive.lowercase
 
 -- | The 'uppercase' transforms all lowercase letters in the input to uppercase, leaving the rest unchanged.
-uppercase :: Monad m => TransducerComponent m Char Char
+uppercase :: Monad m => TransducerComponent m String String
 uppercase = atomic "uppercase" 1 Primitive.uppercase
 
 -- | The 'count' transducer counts all its input values and outputs the final tally.
-count :: Monad m => TransducerComponent m x Integer
+count :: (Monad m, FactorialMonoid x) => TransducerComponent m x [Integer]
 count = atomic "count" 1 Primitive.count
 
 -- | Converts each input value @x@ to @show x@.
-toString :: (Monad m, Show x) => TransducerComponent m x String
+toString :: (Monad m, Show x) => TransducerComponent m [x] [String]
 toString = atomic "toString" 1 Primitive.toString
 
 -- | Performs the same task as the 'substring' splitter, but instead of splitting it outputs the input as @'Markup' x
 -- 'OccurenceTag'@ in order to distinguish overlapping strings.
-parseSubstring :: (Monad m, Eq x) => [x] -> ParserComponent m x OccurenceTag
+parseSubstring :: (Monad m, Eq x, LeftCancellativeMonoid x, FactorialMonoid x) => x -> ParserComponent m x OccurenceTag
 parseSubstring list = atomic "parseSubstring" 1 (Primitive.parseSubstring list)
 
 -- *** List stream transducers
 
--- | TransducerComponent 'group' collects all its input values into a single list.
-group :: Monad m => TransducerComponent m x [x]
+-- | TransducerComponent 'group' collects all its input into a single list item.
+group :: (Monad m, Monoid x) => TransducerComponent m x [x]
 group = atomic "group" 1 Primitive.group
 
 -- | TransducerComponent 'concatenate' flattens the input stream of lists of values into the output stream of values.
-concatenate :: Monad m => TransducerComponent m [x] x
+concatenate :: (Monad m, Monoid x) => TransducerComponent m [x] x
 concatenate = atomic "concatenate" 1 Primitive.concatenate
 
 -- | Same as 'concatenate' except it inserts the given separator list between every two input lists.
-concatSeparate :: Monad m => [x] -> TransducerComponent m [x] x
+concatSeparate :: (Monad m, MonoidNull x) => x -> TransducerComponent m [x] x
 concatSeparate separator = atomic "concatSeparate" 1 (Primitive.concatSeparate separator)
 
 -- ** Generic splitters
 
 -- | SplitterComponent 'everything' feeds its entire input into its /true/ sink.
-everything :: Monad m => SplitterComponent m x ()
+everything :: Monad m => SplitterComponent m x
 everything = atomic "everything" 1 Primitive.everything
 
 -- | SplitterComponent 'nothing' feeds its entire input into its /false/ sink.
-nothing :: Monad m => SplitterComponent m x ()
+nothing :: (Monad m, Monoid x) => SplitterComponent m x
 nothing = atomic "nothing" 1 Primitive.nothing
 
 -- | SplitterComponent 'marked' passes all marked-up input sections to its /true/ sink, and all unmarked input to its
 -- /false/ sink.
-marked :: (Monad m, Eq y) => SplitterComponent m (Markup y x) ()
+marked :: (Monad m, Eq y) => SplitterComponent m [Markup y x]
 marked = atomic "marked" 1 Primitive.marked
 
 -- | SplitterComponent 'markedContent' passes the content of all marked-up input sections to its /true/ sink, while the
 -- outermost tags and all unmarked input go to its /false/ sink.
-markedContent :: (Monad m, Eq y) => SplitterComponent m (Markup y x) ()
+markedContent :: (Monad m, Eq y) => SplitterComponent m [Markup y x]
 markedContent = atomic "markedContent" 1 Primitive.markedContent
 
 -- | SplitterComponent 'markedWith' passes input sections marked-up with the appropriate tag to its /true/ sink, and the
 -- rest of the input to its /false/ sink. The argument /select/ determines if the tag is appropriate.
-markedWith :: (Monad m, Eq y) => (y -> Bool) -> SplitterComponent m (Markup y x) ()
+markedWith :: (Monad m, Eq y) => (y -> Bool) -> SplitterComponent m [Markup y x]
 markedWith selector = atomic "markedWith" 1 (Primitive.markedWith selector)
 
 -- | SplitterComponent 'contentMarkedWith' passes the content of input sections marked-up with the appropriate tag to
 -- its /true/ sink, and the rest of the input to its /false/ sink. The argument /select/ determines if the tag is
 -- appropriate.
-contentMarkedWith :: (Monad m, Eq y) => (y -> Bool) -> SplitterComponent m (Markup y x) ()
+contentMarkedWith :: (Monad m, Eq y) => (y -> Bool) -> SplitterComponent m [Markup y x]
 contentMarkedWith selector = atomic "contentMarkedWith" 1 (Primitive.contentMarkedWith selector)
 
 -- | SplitterComponent 'one' feeds all input values to its /true/ sink, treating every value as a separate section.
-one :: Monad m => SplitterComponent m x ()
+one :: (Monad m, FactorialMonoid x) => SplitterComponent m x
 one = atomic "one" 1 Primitive.one
 
 -- | SplitterComponent 'substring' feeds to its /true/ sink all input parts that match the contents of the given list
 -- argument. If two overlapping parts of the input both match the argument, both are sent to /true/ and each is preceded
--- by an edge.
-substring :: (Monad m, Eq x) => [x] -> SplitterComponent m x ()
+-- by an empty chunk on /false/.
+substring :: (Monad m, Eq x, LeftCancellativeMonoid x, FactorialMonoid x) => x -> SplitterComponent m x
 substring list = atomic "substring" 1 (Primitive.substring list)
 
 -- * Character stream components
 
 -- | SplitterComponent 'whitespace' feeds all white-space characters into its /true/ sink, all others into /false/.
-whitespace :: Monad m => SplitterComponent m Char ()
+whitespace :: Monad m => SplitterComponent m String
 whitespace = atomic "whitespace" 1 Primitive.whitespace
 
 -- | SplitterComponent 'letters' feeds all alphabetical characters into its /true/ sink, all other characters into
 -- | /false/.
-letters :: Monad m => SplitterComponent m Char ()
+letters :: Monad m => SplitterComponent m String
 letters = atomic "letters" 1 Primitive.letters
 
 -- | SplitterComponent 'digits' feeds all digits into its /true/ sink, all other characters into /false/.
-digits :: Monad m => SplitterComponent m Char ()
+digits :: Monad m => SplitterComponent m String
 digits = atomic "digits" 1 Primitive.digits
 
 -- | SplitterComponent 'nonEmptyLine' feeds line-ends into its /false/ sink, and all other characters into /true/.
-nonEmptyLine :: Monad m => SplitterComponent m Char ()
+nonEmptyLine :: Monad m => SplitterComponent m String
 nonEmptyLine = atomic "nonEmptyLine" 1 Primitive.nonEmptyLine
 
 -- | The sectioning splitter 'line' feeds line-ends into its /false/ sink, and line contents into /true/. A single
 -- line-end can be formed by any of the character sequences \"\\n\", \"\\r\", \"\\r\\n\", or \"\\n\\r\".
-line :: Monad m => SplitterComponent m Char ()
+line :: Monad m => SplitterComponent m String
 line = atomic "line" 1 Primitive.line
 
 -- * Consumer, producer, and transducer combinators
 
 -- | Converts a 'ConsumerComponent' into a 'TransducerComponent' with no output.
 consumeBy :: (Monad m) => ConsumerComponent m x r -> TransducerComponent m x y
-consumeBy = lift 1 "consumeBy" Combinator.consumeBy
+consumeBy = Configuration.lift 1 "consumeBy" Combinator.consumeBy
 
 -- | Class 'PipeableComponentPair' applies to any two components that can be combined into a third component with the
 -- following properties:
@@ -278,9 +283,9 @@
 --
 --    * The result output, if any, is the output of the second component.
 
-(>->) :: (MonadParallel m, Combinator.PipeableComponentPair m w c1 c2 c3) => 
+(>->) :: (MonadParallel m, PipeableComponentPair m w c1 c2 c3) => 
          Component c1 -> Component c2 -> Component c3
-(>->) = liftParallelPair ">->" Combinator.compose
+(>->) = liftParallelPair ">->" compose
 
 class CompatibleSignature c cons (m :: * -> *) input output | c -> cons m
 
@@ -315,79 +320,79 @@
 
 -- | The 'sequence' combinator makes sure its first argument has completed before using the second one.
 sequence :: Combinator.JoinableComponentPair t1 t2 t3 m x y c1 c2 c3 => Component c1 -> Component c2 -> Component c3
-sequence = liftSequentialPair "sequence" Combinator.sequence
+sequence = Configuration.liftSequentialPair "sequence" Combinator.sequence
 
 -- | Combinator 'prepend' converts the given producer to transducer that passes all its input through unmodified, except
 -- | for prepending the output of the argument producer to it.
 -- | 'prepend' /prefix/ = 'join' ('substitute' /prefix/) 'asis'
 prepend :: (Monad m) => ProducerComponent m x r -> TransducerComponent m x x
-prepend = lift 1 "prepend" Combinator.prepend
+prepend = Configuration.lift 1 "prepend" Combinator.prepend
 
 -- | Combinator 'append' converts the given producer to transducer that passes all its input through unmodified, finally
 -- | appending to it the output of the argument producer.
 -- | 'append' /suffix/ = 'join' 'asis' ('substitute' /suffix/)
 append :: (Monad m) => ProducerComponent m x r -> TransducerComponent m x x
-append = lift 1 "append" Combinator.append
+append = Configuration.lift 1 "append" Combinator.append
 
 -- | The 'substitute' combinator converts its argument producer to a transducer that produces the same output, while
 -- | consuming its entire input and ignoring it.
-substitute :: (Monad m) => ProducerComponent m y r -> TransducerComponent m x y
-substitute = lift 1 "substitute" Combinator.substitute
+substitute :: (Monad m, Monoid x) => ProducerComponent m y r -> TransducerComponent m x y
+substitute = Configuration.lift 1 "substitute" Combinator.substitute
 
 -- * Splitter combinators
 
 -- | The 'snot' (streaming not) combinator simply reverses the outputs of the argument splitter. In other words, data
 -- that the argument splitter sends to its /true/ sink goes to the /false/ sink of the result, and vice versa.
-snot :: Monad m => SplitterComponent m x b -> SplitterComponent m x b
-snot = lift 1 "not" Combinator.sNot
+snot :: (Monad m, Monoid x) => SplitterComponent m x -> SplitterComponent m x
+snot = Configuration.lift 1 "not" Combinator.sNot
 
 -- ** Pseudo-logic flow combinators
 
 -- | The '>&' combinator sends the /true/ sink output of its left operand to the input of its right operand for further
 -- splitting. Both operands' /false/ sinks are connected to the /false/ sink of the combined splitter, but any input
 -- value to reach the /true/ sink of the combined component data must be deemed true by both splitters.
-(>&) :: MonadParallel m => SplitterComponent m x b1 -> SplitterComponent m x b2 -> SplitterComponent m x (b1, b2)
+(>&) :: (MonadParallel m, Monoid x) => SplitterComponent m x -> SplitterComponent m x -> SplitterComponent m x
 (>&) = liftParallelPair ">&" Combinator.sAnd
 
 -- | A '>|' combinator's input value can reach its /false/ sink only by going through both argument splitters' /false/
 -- sinks.
-(>|) :: MonadParallel m => SplitterComponent m x b1 -> SplitterComponent m x b2 -> SplitterComponent m x (Either b1 b2)
+(>|) :: (MonadParallel m, Monoid x) => SplitterComponent m x -> SplitterComponent m x -> SplitterComponent m x
 (>|) = liftParallelPair ">&" Combinator.sOr
 
 -- ** Zipping logic combinators
 
 -- | Combinator '&&' is a pairwise logical conjunction of two splitters run in parallel on the same input.
-(&&) :: MonadParallel m => SplitterComponent m x b1 -> SplitterComponent m x b2 -> SplitterComponent m x (b1, b2)
+(&&) :: (MonadParallel m, FactorialMonoid x) => SplitterComponent m x -> SplitterComponent m x -> SplitterComponent m x
 (&&) = liftParallelPair "&&" Combinator.pAnd
 
 -- | Combinator '||' is a pairwise logical disjunction of two splitters run in parallel on the same input.
-(||) :: MonadParallel m => SplitterComponent m x b1 -> SplitterComponent m x b2 -> SplitterComponent m x (Either b1 b2)
+(||) :: (MonadParallel m, FactorialMonoid x) => SplitterComponent m x -> SplitterComponent m x -> SplitterComponent m x
 (||) = liftParallelPair "||" Combinator.pOr
 
 -- * Flow-control combinators
 
-ifs :: (MonadParallel m, Branching c m x ()) =>
-       SplitterComponent m x b -> Component c -> Component c -> Component c
+ifs :: (MonadParallel m, Branching c m x ()) => SplitterComponent m x -> Component c -> Component c -> Component c
 ifs = parallelRouterAndBranches "ifs" Combinator.ifs
 
-wherever :: MonadParallel m =>
-            TransducerComponent m x x -> SplitterComponent m x b -> TransducerComponent m x x
+wherever :: (MonadParallel m, Monoid x) =>
+            TransducerComponent m x x -> SplitterComponent m x -> TransducerComponent m x x
 wherever = liftParallelPair "wherever" Combinator.wherever
 
-unless :: MonadParallel m =>
-          TransducerComponent m x x -> SplitterComponent m x b -> TransducerComponent m x x
+unless :: (MonadParallel m, Monoid x) =>
+          TransducerComponent m x x -> SplitterComponent m x -> TransducerComponent m x x
 unless = liftParallelPair "unless" Combinator.unless
 
-select :: Monad m => SplitterComponent m x b -> TransducerComponent m x x
-select = lift 1 "select" Combinator.select
+select :: (Monad m, Monoid x) => SplitterComponent m x -> TransducerComponent m x x
+select = Configuration.lift 1 "select" Combinator.select
 
 -- ** Recursive
 
 -- | The recursive combinator 'while' feeds the true sink of the argument splitter back to itself, modified by the
 -- argument transducer. Data fed to the splitter's false sink is passed on unmodified.
-while :: MonadParallel m =>
-         TransducerComponent m x x -> SplitterComponent m x b -> TransducerComponent m x x
-while t s = recursiveComponentTree "while" (uncurry . Combinator.while) $ liftSequentialPair "pair" (,) t s
+while :: (MonadParallel m, MonoidNull x) =>
+         TransducerComponent m x x -> SplitterComponent m x -> TransducerComponent m x x
+while t s = recursiveComponentTree "while" (uncurry . Combinator.while) 
+            $ Configuration.liftSequentialPair "pair" (,) t s
 
 -- | The recursive combinator 'nestedIn' combines two splitters into a mutually recursive loop acting as a single
 -- splitter.  The true sink of one of the argument splitters and false sink of the other become the true and false sinks
@@ -395,9 +400,9 @@
 -- on hierarchically structured streams. If we gave it some input containing a flat sequence of values, and assuming
 -- both component splitters are deterministic and stateless, an input value would either not loop at all or it would
 -- loop forever.
-nestedIn :: MonadParallel m =>
-            SplitterComponent m x b -> SplitterComponent m x b -> SplitterComponent m x b
-nestedIn s1 s2 = recursiveComponentTree "nestedIn" (uncurry . Combinator.nestedIn) $ liftSequentialPair "pair" (,) s1 s2
+nestedIn :: (MonadParallel m, MonoidNull x) => SplitterComponent m x -> SplitterComponent m x -> SplitterComponent m x
+nestedIn s1 s2 = recursiveComponentTree "nestedIn" (uncurry . Combinator.nestedIn) 
+                 $ Configuration.liftSequentialPair "pair" (,) s1 s2
 
 -- * Section-based combinators
 
@@ -406,8 +411,8 @@
 -- input as the splitter chunks it up. Each contiguous portion of the input that the splitter sends to one of its two
 -- sinks gets transducered through the appropriate argument transducer as that transducer's whole input. As soon as the
 -- contiguous portion is finished, the transducer gets terminated.
-foreach :: (MonadParallel m, Branching c m x ()) =>
-           SplitterComponent m x b -> Component c -> Component c -> Component c
+foreach :: (MonadParallel m, MonoidNull x, Branching c m x ()) =>
+           SplitterComponent m x -> Component c -> Component c -> Component c
 foreach = parallelRouterAndBranches "foreach" Combinator.foreach
 
 -- | The 'having' combinator combines two pure splitters into a pure splitter. One splitter is used to chunk the input
@@ -415,48 +420,49 @@
 -- second splitter is instantiated and run on each portion of the input that goes to first splitter's /true/ sink. If
 -- the second splitter sends any output at all to its /true/ sink, the whole input portion is passed on to the /true/
 -- sink of the combined splitter, otherwise it goes to its /false/ sink.
-having :: (MonadParallel m, Coercible x y) => 
-          SplitterComponent m x b1 -> SplitterComponent m y b2 -> SplitterComponent m x b1
+having :: (MonadParallel m, MonoidNull x, MonoidNull y, Coercible x y) =>
+          SplitterComponent m x -> SplitterComponent m y -> SplitterComponent m x
 having = liftParallelPair "having" Combinator.having
 
 -- | The 'havingOnly' combinator is analogous to the 'having' combinator, but it succeeds and passes each chunk of the
 -- input to its /true/ sink only if the second splitter sends no part of it to its /false/ sink.
-havingOnly :: (MonadParallel m, Coercible x y) => 
-              SplitterComponent m x b1 -> SplitterComponent m y b2 -> SplitterComponent m x b1
+havingOnly :: (MonadParallel m, MonoidNull x, MonoidNull y, Coercible x y) =>
+              SplitterComponent m x -> SplitterComponent m y -> SplitterComponent m x
 havingOnly = liftParallelPair "havingOnly" Combinator.havingOnly
 
 -- | Combinator 'followedBy' treats its argument 'SplitterComponent's as patterns components and returns a
 -- 'SplitterComponent' that matches their concatenation. A section of input is considered /true/ by the result iff its
 -- prefix is considered /true/ by argument /s1/ and the rest of the section is considered /true/ by /s2/. The splitter
 -- /s2/ is started anew after every section split to /true/ sink by /s1/.
-followedBy :: MonadParallel m => SplitterComponent m x b1 -> SplitterComponent m x b2 -> SplitterComponent m x (b1, b2)
+followedBy :: (MonadParallel m, FactorialMonoid x) =>
+              SplitterComponent m x -> SplitterComponent m x -> SplitterComponent m x
 followedBy = liftParallelPair "followedBy" Combinator.followedBy
 
 -- | The 'even' combinator takes every input section that its argument /splitter/ deems /true/, and feeds even ones into
 -- its /true/ sink. The odd sections and parts of input that are /false/ according to its argument splitter are fed to
 -- 'even' splitter's /false/ sink.
-even :: Monad m => SplitterComponent m x b -> SplitterComponent m x b
-even = lift 2 "even" Combinator.even
+even :: (Monad m, MonoidNull x) => SplitterComponent m x -> SplitterComponent m x
+even = Configuration.lift 2 "even" Combinator.even
 
 -- ** first and its variants
 
 -- | The result of combinator 'first' behaves the same as the argument splitter up to and including the first portion of
 -- the input which goes into the argument's /true/ sink. All input following the first true portion goes into the
 -- /false/ sink.
-first :: Monad m => SplitterComponent m x b -> SplitterComponent m x b
-first = lift 2 "first" Combinator.first
+first :: (Monad m, MonoidNull x) => SplitterComponent m x -> SplitterComponent m x
+first = Configuration.lift 2 "first" Combinator.first
 
 -- | The result of combinator 'uptoFirst' takes all input up to and including the first portion of the input which goes
 -- into the argument's /true/ sink and feeds it to the result splitter's /true/ sink. All the rest of the input goes
 -- into the /false/ sink. The only difference between 'first' and 'uptoFirst' combinators is in where they direct the
 -- /false/ portion of the input preceding the first /true/ part.
-uptoFirst :: Monad m => SplitterComponent m x b -> SplitterComponent m x b
-uptoFirst = lift 2 "uptoFirst" Combinator.uptoFirst
+uptoFirst :: (Monad m, MonoidNull x) => SplitterComponent m x -> SplitterComponent m x
+uptoFirst = Configuration.lift 2 "uptoFirst" Combinator.uptoFirst
 
 -- | The 'prefix' combinator feeds its /true/ sink only the prefix of the input that its argument feeds to its /true/
 -- sink.  All the rest of the input is dumped into the /false/ sink of the result.
-prefix :: Monad m => SplitterComponent m x b -> SplitterComponent m x b
-prefix = lift 2 "prefix" Combinator.prefix
+prefix :: (Monad m, MonoidNull x) => SplitterComponent m x -> SplitterComponent m x
+prefix = Configuration.lift 2 "prefix" Combinator.prefix
 
 -- ** last and its variants
 
@@ -465,93 +471,88 @@
 -- the resulting component's /true/ sink.  The splitter returned by the combinator 'last' has to buffer the previous two
 -- portions of its input, because it cannot know if a true portion of the input is the last one until it sees the end of
 -- the input or another portion succeeding the previous one.
-last :: Monad m => SplitterComponent m x b -> SplitterComponent m x b
-last = lift 2 "last" Combinator.last
+last :: (Monad m, MonoidNull x) => SplitterComponent m x -> SplitterComponent m x
+last = Configuration.lift 2 "last" Combinator.last
 
 -- | The result of the combinator 'lastAndAfter' is a splitter which directs all input to its /false/ sink, up to the
 -- last portion of the input which goes to its argument's /true/ sink. That portion and the remainder of the input is
 -- fed to the resulting component's /true/ sink. The difference between 'last' and 'lastAndAfter' combinators is where
 -- they feed the /false/ portion of the input, if any, remaining after the last /true/ part.
-lastAndAfter :: Monad m => SplitterComponent m x b -> SplitterComponent m x b
-lastAndAfter = lift 2 "lastAndAfter" Combinator.lastAndAfter
+lastAndAfter :: (Monad m, MonoidNull x) => SplitterComponent m x -> SplitterComponent m x
+lastAndAfter = Configuration.lift 2 "lastAndAfter" Combinator.lastAndAfter
 
 -- | The 'suffix' combinator feeds its /true/ sink only the suffix of the input that its argument feeds to its /true/
 -- sink.  All the rest of the input is dumped into the /false/ sink of the result.
-suffix :: Monad m => SplitterComponent m x b -> SplitterComponent m x b
-suffix = lift 2 "suffix" Combinator.suffix
+suffix :: (Monad m, MonoidNull x) => SplitterComponent m x -> SplitterComponent m x
+suffix = Configuration.lift 2 "suffix" Combinator.suffix
 
 -- ** positional splitters
 
 -- | SplitterComponent 'startOf' issues an empty /true/ section at the beginning of every section considered /true/ by
 -- its argument splitter, otherwise the entire input goes into its /false/ sink.
-startOf :: Monad m => SplitterComponent m x b -> SplitterComponent m x (Maybe b)
-startOf = lift 2 "startOf" Combinator.startOf
+startOf :: (Monad m, MonoidNull x) => SplitterComponent m x -> SplitterComponent m x
+startOf = Configuration.lift 2 "startOf" Combinator.startOf
 
 -- | SplitterComponent 'endOf' issues an empty /true/ section at the end of every section considered /true/ by its
 -- argument splitter, otherwise the entire input goes into its /false/ sink.
-endOf :: MonadParallel m => SplitterComponent m x b -> SplitterComponent m x (Maybe b)
-endOf = lift 2 "endOf" Combinator.endOf
+endOf :: (Monad m, MonoidNull x) => SplitterComponent m x -> SplitterComponent m x
+endOf = Configuration.lift 2 "endOf" Combinator.endOf
 
 -- | Combinator '...' tracks the running balance of difference between the number of preceding starts of sections
 -- considered /true/ according to its first argument and the ones according to its second argument. The combinator
 -- passes to /true/ all input values for which the difference balance is positive. This combinator is typically used
 -- with 'startOf' and 'endOf' in order to count entire input sections and ignore their lengths.
-(...) :: MonadParallel m => SplitterComponent m x b1 -> SplitterComponent m x b2 -> SplitterComponent m x b1
+(...) :: (MonadParallel m, FactorialMonoid x) => SplitterComponent m x -> SplitterComponent m x -> SplitterComponent m x
 (...) = liftParallelPair "..." Combinator.between
 
 -- * Parser support
 
 -- | Converts a splitter into a parser.
-parseRegions :: Monad m => SplitterComponent m x b -> ParserComponent m x b
-parseRegions = lift 1 "parseRegions" Combinator.parseRegions
-
--- | Converts a boundary-marking splitter into a parser.
-parseNestedRegions :: MonadParallel m =>
-                      SplitterComponent m x (Boundary b) -> ParserComponent m x b
-parseNestedRegions = lift 1 "parseNestedRegions" Combinator.parseNestedRegions
+parseRegions :: (Monad m, MonoidNull x) => SplitterComponent m x -> ParserComponent m x ()
+parseRegions = Configuration.lift 1 "parseRegions" Combinator.parseRegions
 
 -- * Parsing XML
 
 -- | This splitter splits XML markup from data content. It is used by 'parseXMLTokens'.
-xmlTokens :: Monad m => SplitterComponent m Char (Boundary XMLToken)
+xmlTokens :: Monad m => SplitterComponent m Text
 xmlTokens = atomic "XML.tokens" 1 XML.xmlTokens
 
 -- | The XML token parser. This parser converts plain text to parsed text, which is a precondition for using the
 -- remaining XML components.
-xmlParseTokens :: MonadParallel m => TransducerComponent m Char (Markup XMLToken Text)
+xmlParseTokens :: MonadParallel m => TransducerComponent m Text [Markup XMLToken Text]
 xmlParseTokens = atomic "XML.parseTokens" 1 XML.parseXMLTokens
 
 -- * XML splitters
 
 -- | Splits all top-level elements with all their content to /true/, all other input to /false/.
-xmlElement :: Monad m => SplitterComponent m (Markup XMLToken Text) ()
+xmlElement :: Monad m => SplitterComponent m [Markup XMLToken Text]
 xmlElement = atomic "XML.element" 1 XML.xmlElement
 
 -- | Splits the content of all top-level elements to /true/, their tags and intervening input to /false/.
-xmlElementContent :: Monad m => SplitterComponent m (Markup XMLToken Text) ()
+xmlElementContent :: Monad m => SplitterComponent m [Markup XMLToken Text]
 xmlElementContent = atomic "XML.elementContent" 1 XML.xmlElementContent
 
 -- | Similiar to @('Control.Concurrent.SCC.Combinators.having' 'element')@, except it runs the argument splitter
 -- only on each element's start tag, not on the entire element with its content.
 xmlElementHavingTagWith :: MonadParallel m =>
-                       SplitterComponent m (Markup XMLToken Text) b -> SplitterComponent m (Markup XMLToken Text) b
-xmlElementHavingTagWith = lift 2 "XML.elementHavingTag" XML.xmlElementHavingTagWith
+                       SplitterComponent m [Markup XMLToken Text] -> SplitterComponent m [Markup XMLToken Text]
+xmlElementHavingTagWith = Configuration.lift 2 "XML.elementHavingTag" XML.xmlElementHavingTagWith
 
 -- | Splits every attribute specification to /true/, everything else to /false/.
-xmlAttribute :: Monad m => SplitterComponent m (Markup XMLToken Text) ()
+xmlAttribute :: Monad m => SplitterComponent m [Markup XMLToken Text]
 xmlAttribute = atomic "XML.attribute" 1 XML.xmlAttribute
 
 -- | Splits every element name, including the names of nested elements and names in end tags, to /true/, all the rest of
 -- input to /false/.
-xmlElementName :: Monad m => SplitterComponent m (Markup XMLToken Text) ()
+xmlElementName :: Monad m => SplitterComponent m [Markup XMLToken Text]
 xmlElementName = atomic "XML.elementName" 1 XML.xmlElementName
 
 -- | Splits every attribute name to /true/, all the rest of input to /false/.
-xmlAttributeName :: Monad m => SplitterComponent m (Markup XMLToken Text) ()
+xmlAttributeName :: Monad m => SplitterComponent m [Markup XMLToken Text]
 xmlAttributeName = atomic "XML.attributeName" 1 XML.xmlAttributeName
 
 -- | Splits every attribute value, excluding the quote delimiters, to /true/, all the rest of input to /false/.
-xmlAttributeValue :: Monad m => SplitterComponent m (Markup XMLToken Text) ()
+xmlAttributeValue :: Monad m => SplitterComponent m [Markup XMLToken Text]
 xmlAttributeValue = atomic "XML.attributeValue" 1 XML.xmlAttributeValue
 
 liftParallelPair :: MonadParallel m => 
diff --git a/Control/Concurrent/SCC/Parallel.hs b/Control/Concurrent/SCC/Parallel.hs
--- a/Control/Concurrent/SCC/Parallel.hs
+++ b/Control/Concurrent/SCC/Parallel.hs
@@ -1,5 +1,5 @@
 {- 
-    Copyright 2008-2010 Mario Blazevic
+    Copyright 2008-2013 Mario Blazevic
 
     This file is part of the Streaming Component Combinators (SCC) project.
 
@@ -14,11 +14,10 @@
     <http://www.gnu.org/licenses/>.
 -}
 
--- | This module exports all of the SCC libraries. The exported combinators run their components in parallel.
+-- | This module exports the entire SCC library except for low-level modules "Control.Concurrent.SCC.Streams" and
+-- "Control.Concurrent.SCC.Types". The exported combinators run their components in parallel.
 
 module Control.Concurrent.SCC.Parallel (
-   module Control.Concurrent.SCC.Streams,
-   module Control.Concurrent.SCC.Types,
    module Control.Concurrent.SCC.Coercions,
    module Control.Concurrent.SCC.Primitives,
    module Control.Concurrent.SCC.Combinators.Parallel,
@@ -26,8 +25,6 @@
 )
 where
 
-import Control.Concurrent.SCC.Streams
-import Control.Concurrent.SCC.Types
 import Control.Concurrent.SCC.Coercions
 import Control.Concurrent.SCC.Primitives
 import Control.Concurrent.SCC.Combinators.Parallel
diff --git a/Control/Concurrent/SCC/Primitives.hs b/Control/Concurrent/SCC/Primitives.hs
--- a/Control/Concurrent/SCC/Primitives.hs
+++ b/Control/Concurrent/SCC/Primitives.hs
@@ -1,5 +1,5 @@
 {- 
-    Copyright 2008-2011 Mario Blazevic
+    Copyright 2008-2013 Mario Blazevic
 
     This file is part of the Streaming Component Combinators (SCC) project.
 
@@ -27,9 +27,9 @@
    -- ** I/O consumers
    appendFile, toFile, toHandle, toStdOut, toBinaryHandle,
    -- * Generic components
-   fromList, 
+   produceFrom, 
    -- ** Generic consumers
-   suppress, erroneous, toList,
+   suppress, erroneous, consumeInto,
    -- ** Generic transducers
    parse, unparse, parseSubstring, OccurenceTag, count, toString,
    -- *** List stream transducers
@@ -46,7 +46,7 @@
    )
 where
 
-import Prelude hiding (appendFile, head, tail)
+import Prelude hiding (appendFile, getLine, length, null, putStr, tail)
 
 import Control.Applicative (Alternative ((<|>)))
 import Control.Exception (assert)
@@ -54,12 +54,17 @@
 import Control.Monad.Trans.Class (lift)
 import Data.ByteString (ByteString)
 import Data.Char (isAlpha, isDigit, isSpace, toLower, toUpper)
-import Data.List (delete, stripPrefix)
+import Data.List (delete)
+import Data.Monoid (Monoid(mappend, mempty), Sum(Sum))
 import qualified Data.ByteString as ByteString
 import qualified Data.Foldable as Foldable
-import System.IO (Handle, IOMode (ReadMode, WriteMode, AppendMode), 
-                  openFile, hClose, hGetLine, hPutStr, hIsEOF, hClose, isEOF)
+import System.IO (Handle, IOMode (ReadMode, WriteMode, AppendMode), openFile, hClose, hIsEOF, hClose, isEOF)
+import Data.Text (Text, singleton)
+import Data.Text.IO (getLine, hGetLine, hPutStr, putStr)
 
+import Data.Monoid.Null (MonoidNull(null))
+import Data.Monoid.Cancellative (LeftReductiveMonoid (stripPrefix))
+import Data.Monoid.Factorial (FactorialMonoid(splitPrimePrefix), length)
 import Text.ParserCombinators.Incremental (string, takeWhile, (<<|>))
 
 import Control.Concurrent.SCC.Streams
@@ -67,161 +72,167 @@
 
 import Debug.Trace (trace)
 
--- | Collects the entire input source into a list.
-toList :: forall m x. Monad m => Consumer m x [x]
-toList = Consumer getList
+-- | Collects the entire input source into the return value.
+consumeInto :: forall m x. (Monad m, Monoid x) => Consumer m x x
+consumeInto = Consumer getAll
 
--- | Produces the contents of the given list argument.
-fromList :: forall m x. Monad m => [x] -> Producer m x ()
-fromList l = Producer ((>> return ()) . putList l)
+-- | Produces the contents of the given argument.
+produceFrom :: forall m x. (Monad m, MonoidNull x) => x -> Producer m x ()
+produceFrom l = Producer ((>> return ()) . putAll l)
 
 -- | Consumer 'toStdOut' copies the given source into the standard output.
-toStdOut :: Consumer IO Char ()
+toStdOut :: Consumer IO Text ()
 toStdOut = Consumer (mapMStreamChunks_ (lift . putStr))
 
 -- | Producer 'fromStdIn' feeds the given sink from the standard input.
-fromStdIn :: Producer IO Char ()
-fromStdIn = Producer (unmapMStreamChunks_ (lift $ isEOF >>= cond (return []) (fmap (++ "\n") getLine)))
+fromStdIn :: Producer IO Text ()
+fromStdIn = Producer (unmapMStreamChunks_ (lift $
+                                           isEOF >>= cond (return mempty) (fmap (`mappend` singleton '\n') getLine)))
 
 -- | Reads the named file and feeds the given sink from its contents.
-fromFile :: String -> Producer IO Char ()
+fromFile :: String -> Producer IO Text ()
 fromFile path = Producer $ \sink-> do handle <- lift (openFile path ReadMode)
                                       produce (fromHandle handle) sink
                                       lift (hClose handle)
 
 -- | Feeds the given sink from the open text file /handle/.
-fromHandle :: Handle -> Producer IO Char ()
+fromHandle :: Handle -> Producer IO Text ()
 fromHandle handle = Producer (unmapMStreamChunks_
-                                 (lift $ hIsEOF handle >>= cond (return []) (fmap (++ "\n") $ hGetLine handle)))
+                                 (lift $
+                                  hIsEOF handle
+                                  >>= cond (return mempty) (fmap (`mappend` singleton '\n') $ hGetLine handle)))
 
 -- | Feeds the given sink from the open binary file /handle/. The argument /chunkSize/ determines the size of the chunks
 -- read from the handle.
 fromBinaryHandle :: Handle -> Int -> Producer IO ByteString ()
 fromBinaryHandle handle chunkSize = Producer p
    where p sink = lift (ByteString.hGet handle chunkSize) 
-                  >>= \chunk-> unless (ByteString.null chunk) (tryPut sink chunk >>= flip when (p sink))
+                  >>= \chunk-> unless (ByteString.null chunk) 
+                                      (putChunk sink chunk 
+                                       >>= \c-> when (ByteString.null c) (p sink))
 
 -- | Creates the named text file and writes the entire given source to it.
-toFile :: String -> Consumer IO Char ()
+toFile :: String -> Consumer IO Text ()
 toFile path = Consumer $ \source-> do handle <- lift (openFile path WriteMode)
                                       consume (toHandle handle) source
                                       lift (hClose handle)
 
 -- | Appends the given source to the named text file.
-appendFile :: String -> Consumer IO Char ()
+appendFile :: String -> Consumer IO Text ()
 appendFile path = Consumer $ \source-> do handle <- lift (openFile path AppendMode)
                                           consume (toHandle handle) source
                                           lift (hClose handle)
 
 -- | Copies the given source into the open text file /handle/.
-toHandle :: Handle -> Consumer IO Char ()
+toHandle :: Handle -> Consumer IO Text ()
 toHandle handle = Consumer (mapMStreamChunks_ (lift . hPutStr handle))
 
 -- | Copies the given source into the open binary file /handle/.
 toBinaryHandle :: Handle -> Consumer IO ByteString ()
-toBinaryHandle handle = Consumer (mapMStream_ (lift . ByteString.hPut handle))
+toBinaryHandle handle = Consumer (mapMStreamChunks_ (lift . ByteString.hPut handle))
 
 -- | Transducer 'unparse' removes all markup from its input and passes the content through.
-unparse :: forall m x b. Monad m => Transducer m (Markup b x) x
+unparse :: forall m x b. (Monad m, Monoid x) => Transducer m [Markup b x] x
 unparse = statelessTransducer removeTag
-   where removeTag (Content x) = [x]
-         removeTag _ = []
+   where removeTag (Content x) = x
+         removeTag _ = mempty
 
 -- | Transducer 'parse' prepares input content for subsequent parsing.
-parse :: forall m x y. Monad m => Transducer m x (Markup y x)
-parse = oneToOneTransducer Content
+parse :: forall m x y. (Monad m, Monoid x) => Parser m x y
+parse = statelessChunkTransducer ((: []) . Content)
 
 -- | The 'suppress' consumer suppresses all input it receives. It is equivalent to 'substitute' []
 suppress :: forall m x. Monad m => Consumer m x ()
-suppress = Consumer (\(src :: Source m a x)-> pour src (nullSink :: Sink m a x))
+suppress = Consumer (\(src :: Source m a x)-> pour_ src (nullSink :: Sink m a x))
 
 -- | The 'erroneous' consumer reports an error if any input reaches it.
-erroneous :: forall m x. Monad m => String -> Consumer m x ()
-erroneous message = Consumer (getWith (const (error message)))
+erroneous :: forall m x. (Monad m, MonoidNull x) => String -> Consumer m x ()
+erroneous message = Consumer (mapMStreamChunks_ (\x-> unless (null x) (error message)))
 
 -- | The 'lowercase' transforms all uppercase letters in the input to lowercase, leaving the rest unchanged.
-lowercase :: forall m. Monad m => Transducer m Char Char
-lowercase = oneToOneTransducer toLower
+lowercase :: forall m. Monad m => Transducer m String String
+lowercase = statelessChunkTransducer (map toLower)
 
 -- | The 'uppercase' transforms all lowercase letters in the input to uppercase, leaving the rest unchanged.
-uppercase :: forall m. Monad m => Transducer m Char Char
-uppercase = oneToOneTransducer toUpper
+uppercase :: forall m. Monad m => Transducer m String String
+uppercase = statelessChunkTransducer (map toUpper)
 
 -- | The 'count' transducer counts all its input values and outputs the final tally.
-count :: forall m x. Monad m => Transducer m x Integer
+count :: forall m x. (Monad m, FactorialMonoid x) => Transducer m x [Integer]
 count = Transducer (\source sink-> foldStream (\n _-> succ n) 0 source >>= put sink)
 
 -- | Converts each input value @x@ to @show x@.
-toString :: forall m x. (Monad m, Show x) => Transducer m x String
-toString = oneToOneTransducer show
+toString :: forall m x. (Monad m, Show x) => Transducer m [x] [String]
+toString = oneToOneTransducer (map show)
 
--- | Transducer 'group' collects all its input values into a single list.
-group :: forall m x. Monad m => Transducer m x [x]
-group = Transducer (\source sink-> getList source >>= put sink)
+-- | Transducer 'group' collects all its input into a single list item.
+group :: forall m x. (Monad m, Monoid x) => Transducer m x [x]
+group = Transducer (\source sink-> getAll source >>= put sink)
 
 -- | Transducer 'concatenate' flattens the input stream of lists of values into the output stream of values.
-concatenate :: forall m x. Monad m => Transducer m [x] x
+concatenate :: forall m x. (Monad m, Monoid x) => Transducer m [x] x
 concatenate = statelessTransducer id
 
 -- | Same as 'concatenate' except it inserts the given separator list between every two input lists.
-concatSeparate :: forall m x. Monad m => [x] -> Transducer m [x] x
-concatSeparate separator = statefulTransducer (\seen list-> (True, if seen then separator ++ list else list))
+concatSeparate :: forall m x. (Monad m, MonoidNull x) => x -> Transducer m [x] x
+concatSeparate separator = statefulTransducer (\seen chunk-> (True, if seen then mappend separator chunk else chunk))
                                               False
 
 -- | Splitter 'whitespace' feeds all white-space characters into its /true/ sink, all others into /false/.
-whitespace :: forall m. Monad m => Splitter m Char ()
+whitespace :: forall m. Monad m => Splitter m String
 whitespace = statelessSplitter isSpace
 
 -- | Splitter 'letters' feeds all alphabetical characters into its /true/ sink, all other characters into
 -- | /false/.
-letters :: forall m. Monad m => Splitter m Char ()
+letters :: forall m. Monad m => Splitter m String
 letters = statelessSplitter isAlpha
 
 -- | Splitter 'digits' feeds all digits into its /true/ sink, all other characters into /false/.
-digits :: forall m. Monad m => Splitter m Char ()
+digits :: forall m. Monad m => Splitter m String
 digits = statelessSplitter isDigit
 
 -- | Splitter 'nonEmptyLine' feeds line-ends into its /false/ sink, and all other characters into /true/.
-nonEmptyLine :: forall m. Monad m => Splitter m Char ()
+nonEmptyLine :: forall m. Monad m => Splitter m String
 nonEmptyLine = statelessSplitter (\ch-> ch /= '\n' && ch /= '\r')
 
 -- | The sectioning splitter 'line' feeds line-ends into its /false/ sink, and line contents into /true/. A single
 -- line-end can be formed by any of the character sequences \"\\n\", \"\\r\", \"\\r\\n\", or \"\\n\\r\".
-line :: forall m. Monad m => Splitter m Char ()
-line = Splitter $ \source true false boundaries->
+line :: forall m. Monad m => Splitter m String
+line = Splitter $ \source true false->
        let loop = peek source >>= maybe (return ()) (( >> loop) . splitLine)
            lineChar c = c /= '\r' && c /= '\n'
            lineEndParser = string "\r\n" <<|> string "\n\r" <<|> string "\r" <<|> string "\n"
-           splitLine c = put boundaries ()
-                         >> when (lineChar c) (pourWhile lineChar source true)
-                         >> pourTicked lineEndParser source false
+           splitLine c = if lineChar c then pourWhile (lineChar . head) source true else putChunk true mempty
+                         >> pourParsed lineEndParser source false
        in loop
 
 -- | Splitter 'everything' feeds its entire input into its /true/ sink.
-everything :: forall m x. Monad m => Splitter m x ()
-everything = Splitter (\source true _false edge-> put edge () >> pour source true)
+everything :: forall m x. Monad m => Splitter m x
+everything = Splitter (\source true _false-> pour source true >>= flip unless (putChunk true mempty >> return ()))
 
 -- | Splitter 'nothing' feeds its entire input into its /false/ sink.
-nothing :: forall m x. Monad m => Splitter m x ()
-nothing = Splitter (\source _true false _edge-> pour source false)
+nothing :: forall m x. (Monad m, Monoid x) => Splitter m x
+nothing = Splitter (\source _true false-> pour_ source false)
 
 -- | Splitter 'one' feeds all input values to its /true/ sink, treating every value as a separate section.
-one :: forall m x. Monad m => Splitter m x ()
-one = Splitter (\source true _false edge-> mapMStream_ (\x-> put edge () >> put true x) source)
+one :: forall m x. (Monad m, FactorialMonoid x) => Splitter m x
+one = Splitter (\source true false-> getWith source $
+                                     \x-> putChunk true x
+                                          >> mapMStream_ (\x-> putChunk false mempty >> putChunk true x) source)
 
 -- | Splitter 'marked' passes all marked-up input sections to its /true/ sink, and all unmarked input to its
 -- /false/ sink.
-marked :: forall m x y. (Monad m, Eq y) => Splitter m (Markup y x) ()
+marked :: forall m x y. (Monad m, Eq y) => Splitter m [Markup y x]
 marked = markedWith (const True)
 
 -- | Splitter 'markedContent' passes the content of all marked-up input sections to its /true/ sink, takeWhile the
 -- outermost tags and all unmarked input go to its /false/ sink.
-markedContent :: forall m x y. (Monad m, Eq y) => Splitter m (Markup y x) ()
+markedContent :: forall m x y. (Monad m, Eq y) => Splitter m [Markup y x]
 markedContent = contentMarkedWith (const True)
 
 -- | Splitter 'markedWith' passes input sections marked-up with the appropriate tag to its /true/ sink, and the
 -- rest of the input to its /false/ sink. The argument /select/ determines if the tag is appropriate.
-markedWith :: forall m x y. (Monad m, Eq y) => (y -> Bool) -> Splitter m (Markup y x) ()
+markedWith :: forall m x y. (Monad m, Eq y) => (y -> Bool) -> Splitter m [Markup y x]
 markedWith select = statefulSplitter transition ([], False)
    where transition s@([], _)     Content{} = (s, False)
          transition s@(_, truth)  Content{} = (s, truth)
@@ -234,7 +245,7 @@
 -- | Splitter 'contentMarkedWith' passes the content of input sections marked-up with the appropriate tag to
 -- its /true/ sink, and the rest of the input to its /false/ sink. The argument /select/ determines if the tag is
 -- appropriate.
-contentMarkedWith :: forall m x y. (Monad m, Eq y) => (y -> Bool) -> Splitter m (Markup y x) ()
+contentMarkedWith :: forall m x y. (Monad m, Eq y) => (y -> Bool) -> Splitter m [Markup y x]
 contentMarkedWith select = statefulSplitter transition ([], False)
    where transition s@(_, truth)  Content{} = (s, truth)
          transition s@(_, truth)  (Markup Point{}) = (s, truth)
@@ -255,71 +266,79 @@
 
 -- | Performs the same task as the 'substring' splitter, but instead of splitting it outputs the input as @'Markup' x
 -- 'OccurenceTag'@ in order to distinguish overlapping strings.
-parseSubstring :: forall m x. (Monad m, Eq x) => [x] -> Parser m x OccurenceTag
-parseSubstring [] = Transducer $ 
-                    \ source sink -> put sink marker >> concatMapStream (\x-> [Content x, marker]) source sink
-   where marker = Markup (Point (toEnum 1))
-parseSubstring list@(first:rest)
-   = Transducer $
-     \ source sink ->
-        let findFirst = pourWhile (/= first) source (mapSink Content sink)
-                        >> test
-            test = getTicked (string list) source
-                   >>= \s-> case s
-                            of [] -> get source >>= maybe (return ()) (\x-> put sink (Content x) >> findFirst)
-                               _ -> put sink (Markup (Start (toEnum 0)))
-                                    >> putList prefixContent sink
-                                    >> if null shared then put sink (Markup (End (toEnum 0))) >> findFirst
-                                       else testOverlap 0
-            testOverlap n = getTicked (string postfix) source
-                            >>= \s-> case s
-                                     of [] -> forM_ [n - maxOverlaps + 1 .. n]
-                                                    (\i-> putList sharedContent sink
-                                                          >> put sink (Markup (End (toEnum i))))
-                                              >> findFirst
-                                        _ -> let n' = succ n
-                                             in put sink (Markup (Start (toEnum n')))
-                                                >> putList prefixContent sink
-                                                >> when (n' >= maxOverlaps) 
-                                                        (put sink (Markup (End (toEnum (n' - maxOverlaps)))))
-                                                >> testOverlap n'
-            (prefix, shared, postfix) = overlap list list
-            maxOverlaps = (length list - 1) `div` length prefix
-            prefixContent = map Content prefix
-            sharedContent = map Content shared
-        in findFirst
+parseSubstring :: forall m x. (Monad m, Eq x, LeftReductiveMonoid x, FactorialMonoid x) => x -> Parser m x OccurenceTag
+parseSubstring s = 
+   case splitPrimePrefix s
+   of Nothing -> Transducer $ 
+                 \ source sink -> put sink marker >> mapStream (\x-> [Content x, marker]) source sink
+         where marker = Markup (Point (toEnum 1))
+      Just (first, rest)->
+         isolateTransducer $ \ source sink ->
+         pipe (\sink'->
+                let findFirst = pourWhile (/= first) source sink'
+                                >> test
+                    test = getParsed (string s) source
+                           >>= \t-> if null t
+                                    then getWith source (\x-> put sink (Content x) >> findFirst)
+                                    else put sink (Markup (Start (toEnum 0)))
+                                         >> put sink prefixContent
+                                         >> if null shared then put sink (Markup (End (toEnum 0))) >> findFirst
+                                            else testOverlap 0
+                    testOverlap n = getParsed (string postfix) source
+                                    >>= \t-> if null t
+                                             then forM_ [n - maxOverlaps + 1 .. n]
+                                                        (\i-> put sink sharedContent
+                                                              >> put sink (Markup (End (toEnum i))))
+                                                      >> findFirst
+                                             else let n' = succ n
+                                                  in put sink (Markup (Start (toEnum n')))
+                                                     >> put sink prefixContent
+                                                     >> when (n' >= maxOverlaps)
+                                                             (put sink (Markup (End (toEnum (n' - maxOverlaps)))))
+                                                     >> testOverlap n'
+                    (prefix, shared, postfix) = overlap s s
+                    maxOverlaps = (length s - 1) `div` length prefix
+                    prefixContent = Content prefix
+                    sharedContent = Content shared
+                in findFirst)
+              (\src-> mapStreamChunks ((: []) . Content) src sink)
+         >> return ()
 
 -- | Splitter 'substring' feeds to its /true/ sink all input parts that match the contents of the given list
 -- argument. If two overlapping parts of the input both match the argument, both are sent to /true/ and each is preceded
--- by an edge.
-substring :: forall m x. (Monad m, Eq x) => [x] -> Splitter m x ()
-substring [] = Splitter $ \ source true false edge -> split one source false true edge >> put edge ()
-substring list@(first:rest)
-   = Splitter $
-     \ source true false edge ->
-        let findFirst = pourWhile (/= first) source false
-                        >> test
-            test = getTicked (string list) source
-                   >>= \s-> case s
-                            of [] -> get source >>= maybe (return ()) (\x-> put false x >> findFirst)
-                               _ -> put edge ()
-                                    >> putList prefix true
-                                    >> if null shared then findFirst else testOverlap
-            testOverlap = getTicked (string postfix) source
-                          >>= \s-> case s
-                                   of [] -> putList shared true >> findFirst
-                                      _ -> put edge ()
-                                           >> putList prefix true 
-                                           >> testOverlap
-            (prefix, shared, postfix) = overlap list list
-        in findFirst
+-- by an empty chunk on /false/.
+substring :: forall m x. (Monad m, Eq x, LeftReductiveMonoid x, FactorialMonoid x) => x -> Splitter m x
+substring s = 
+   Splitter $ \ source true false ->
+   case splitPrimePrefix s
+   of Nothing -> putChunk true mempty
+                 >> mapMStream_ (\x-> putChunk false x >> putChunk true mempty) source
+      Just (first, rest) ->
+         let findFirst = pourWhile (/= first) source false
+                         >> test
+             test = getParsed (string s) source
+                    >>= \t-> if null t
+                             then getWith source (\x-> putChunk false x >> findFirst)
+                             else putChunk false mempty
+                                  >> putAll prefix true
+                                  >> if null shared then findFirst else testOverlap
+             testOverlap = getParsed (string postfix) source
+                           >>= \t-> if null t
+                                    then putAll shared true >> findFirst
+                                    else putChunk false mempty
+                                         >> putAll prefix true
+                                         >> testOverlap
+             (prefix, shared, postfix) = overlap s s
+         in findFirst
 
-overlap :: Eq x => [x] -> [x] -> ([x], [x], [x])
-overlap [] s = ([], [], s)
-overlap (head:tail) s2 = case stripPrefix tail s2
-                         of Just rest -> ([head], tail, rest)
-                            Nothing -> let (o1, o2, o3) = overlap tail s2
-                                       in (head:o1, o2, o3)
+overlap :: (LeftReductiveMonoid x, FactorialMonoid x) => x -> x -> (x, x, x)
+overlap e s | null e = (e, e, s)
+overlap s1 s2 = case splitPrimePrefix s1
+                of Nothing -> (s1, s1, s2)
+                   Just (head, tail) -> case stripPrefix tail s2
+                                        of Just rest -> (head, tail, rest)
+                                           Nothing -> let (o1, o2, o3) = overlap tail s2
+                                                      in (mappend head o1, o2, o3)
 
 -- | A utility function wrapping if-then-else, useful for handling monadic truth values
 cond :: a -> a -> Bool -> a
diff --git a/Control/Concurrent/SCC/Sequential.hs b/Control/Concurrent/SCC/Sequential.hs
--- a/Control/Concurrent/SCC/Sequential.hs
+++ b/Control/Concurrent/SCC/Sequential.hs
@@ -1,5 +1,5 @@
 {- 
-    Copyright 2008-2010 Mario Blazevic
+    Copyright 2008-2013 Mario Blazevic
 
     This file is part of the Streaming Component Combinators (SCC) project.
 
@@ -14,12 +14,10 @@
     <http://www.gnu.org/licenses/>.
 -}
 
--- | This module exports all of the SCC libraries. The exported combinators run their components by sequentially
--- interleaving them.
+-- | This module exports the entire SCC library except for low-level modules "Control.Concurrent.SCC.Streams" and
+-- "Control.Concurrent.SCC.Types". The exported combinators run their components by sequentially interleaving them.
 
 module Control.Concurrent.SCC.Sequential (
-   module Control.Concurrent.SCC.Streams,
-   module Control.Concurrent.SCC.Types,
    module Control.Concurrent.SCC.Coercions,
    module Control.Concurrent.SCC.Primitives,
    module Control.Concurrent.SCC.Combinators.Sequential,
@@ -27,8 +25,6 @@
 )
 where
 
-import Control.Concurrent.SCC.Streams
-import Control.Concurrent.SCC.Types
 import Control.Concurrent.SCC.Coercions
 import Control.Concurrent.SCC.Primitives
 import Control.Concurrent.SCC.Combinators.Sequential
diff --git a/Control/Concurrent/SCC/Streams.hs b/Control/Concurrent/SCC/Streams.hs
--- a/Control/Concurrent/SCC/Streams.hs
+++ b/Control/Concurrent/SCC/Streams.hs
@@ -1,5 +1,5 @@
-{- 
-    Copyright 2010-2011 Mario Blazevic
+{-
+    Copyright 2010-2013 Mario Blazevic
 
     This file is part of the Streaming Component Combinators (SCC) project.
 
@@ -15,57 +15,59 @@
 -}
 
 -- | This module defines 'Source' and 'Sink' types and 'pipe' functions that create them. The method 'get' on 'Source'
--- abstracts away 'Control.Concurrent.Coroutine.SuspensionFunctors.await', and the method 'put' on 'Sink' is a
--- higher-level abstraction of 'Control.Concurrent.Coroutine.SuspensionFunctors.yield'. With this arrangement, a single
--- coroutine can yield values to multiple sinks and await values from multiple sources with no need to change the
--- 'Control.Concurrent.Coroutine.Coroutine' functor; the only requirement is for each funtor of the sources and sinks
--- the coroutine uses to be an 'Control.Concurrent.Coroutine.AncestorFunctor' of the coroutine's functor. For example,
--- coroutine /zip/ that takes two sources and one sink would be declared like this:
+-- abstracts away 'Control.Monad.Coroutine.SuspensionFunctors.await', and the method 'put' on 'Sink' is a higher-level
+-- abstraction of 'Control.Monad.Coroutine.SuspensionFunctors.yield'. With this arrangement, a single coroutine can
+-- yield values to multiple sinks and await values from multiple sources with no need to change the
+-- 'Control.Monad.Coroutine.Coroutine' functor. The only requirement is that each functor of the sources and sinks the
+-- coroutine uses must be an 'Control.Monad.Coroutine.Nested.AncestorFunctor' of the coroutine's own functor. For
+-- example, a coroutine that takes two sources and one sink might be declared like this:
 -- 
 -- @
 -- zip :: forall m a1 a2 a3 d x y. (Monad m, AncestorFunctor a1 d, AncestorFunctor a2 d, AncestorFunctor a3 d)
---        => Source m a1 x -> Source m a2 y -> Sink m a3 (x, y) -> Coroutine d m ()
+--        => Source m a1 [x] -> Source m a2 [y] -> Sink m a3 [(x, y)] -> Coroutine d m ()
 -- @
 -- 
 -- Sources, sinks, and coroutines communicating through them are all created using the 'pipe' function or one of its
 -- variants. They effectively split the current coroutine into a producer-consumer coroutine pair. The producer gets a
--- new 'Sink' to write to and the consumer a new 'Source' to read from, in addition to all the streams that are visible
--- in the original coroutine. The following function, for example, uses the /zip/ coroutine above to add together the
--- values from two Integer sources:
+-- new 'Sink' to write to and the consumer a new 'Source' to read from, in addition to all the streams they inherit from
+-- the current coroutine. The following function, for example, uses the /zip/ coroutine declard above to add together
+-- the pairs of values from two Integer sources:
 --
 -- @
 -- add :: forall m a1 a2 a3 d. (Monad m, AncestorFunctor a1 d, AncestorFunctor a2 d, AncestorFunctor a3 d)
---        => Source m a1 Integer -> Source m a2 Integer -> Sink m a3 Integer -> Coroutine d m ()
+--        => Source m a1 [Integer] -> Source m a2 [Integer] -> Sink m a3 [Integer] -> Coroutine d m ()
 -- add source1 source2 sink = do pipe
---                                  (\pairSink-> zip source1 source2 pairSink)              -- producer coroutine
---                                  (\pairSource-> mapStream (uncurry (+)) pairSource sink) -- consumer coroutine
+--                                  (\pairSink-> zip source1 source2 pairSink)                         -- producer
+--                                  (\pairSource-> mapStream (List.map $ uncurry (+)) pairSource sink) -- consumer
 --                               return ()
 -- @
 
 {-# LANGUAGE ScopedTypeVariables, Rank2Types, TypeFamilies, KindSignatures #-}
-{-# OPTIONS_HADDOCK hide #-}
 
 module Control.Concurrent.SCC.Streams
    (
     -- * Sink and Source types
     Sink, Source, SinkFunctor, SourceFunctor, AncestorFunctor,
     -- * Sink and Source constructors
-    pipe, pipeP, pipeG, nullSink, nullSource,
+    pipe, pipeP, pipeG, nullSink,
     -- * Operations on sinks and sources
     -- ** Singleton operations
-    get, getWith, peek, put, tryPut,
+    get, getWith, getPrime, peek, put, tryPut,
     -- ** Lifting functions
     liftSink, liftSource,
     -- ** Bulk operations
     -- *** Fetching and moving data
-    pour, tee, teeSink,
-    getList, putList, putQueue,
-    getTicked, getWhile, getUntil, 
-    pourTicked, pourParsed, pourWhile, pourUntil,
+    pour, pour_, tee, teeSink,
+    getAll, putAll, putChunk,
+    getParsed, getRead,
+    getWhile, getUntil, 
+    pourRead, pourParsed, pourWhile, pourUntil,
+    Reader, Reading(..), ReadingResult(..),
     -- *** Stream transformations
+    markDown, markUpWith,
     mapSink, mapStream,
     mapMaybeStream, concatMapStream,
-    mapStreamChunks, foldStream, mapAccumStream, concatMapAccumStream, partitionStream,
+    mapStreamChunks, mapAccumStreamChunks, foldStream, mapAccumStream, concatMapAccumStream, partitionStream,
     -- *** Monadic stream transformations
     mapMStream, mapMStream_, mapMStreamChunks_,
     filterMStream, foldMStream, foldMStream_, unfoldMStream, unmapMStream_, unmapMStreamChunks_,
@@ -73,191 +75,280 @@
    )
 where
 
-import Prelude hiding (takeWhile)
-  
+import Prelude hiding (foldl, foldr, map, mapM, mapM_, null, span, takeWhile)
+
 import qualified Control.Monad
 import Control.Monad (liftM, when, unless, foldM)
-import Data.Foldable (toList)
-import Data.Monoid (Monoid, mempty, First(First, getFirst))
-import Data.Monoid.Null (MonoidNull)
+import Data.Functor.Identity (Identity(..))
+import Data.Monoid (Monoid(mappend, mconcat, mempty), First(First, getFirst))
+import Data.Monoid.Factorial (FactorialMonoid, foldl, map, mapM, mapM_, span, primePrefix, splitPrimePrefix)
+import Data.Monoid.Null (MonoidNull(null))
 import Data.Maybe (mapMaybe)
 import Data.List (mapAccumL)
-import Data.Sequence (Seq, viewl)
-import Text.ParserCombinators.Incremental
+import qualified Data.List as List (map, span)
+import Text.ParserCombinators.Incremental (Parser, feed, feedEof, inspect, completeResults)
 
 import Control.Monad.Parallel (MonadParallel(..))
 import Control.Monad.Coroutine
-import Control.Monad.Coroutine.SuspensionFunctors (EitherFunctor(..), Request, request, ParseRequest, requestParse,
-                                                   nestedLazyParserRequestResolver)
-import Control.Monad.Coroutine.Nested (AncestorFunctor(..), liftAncestor, seesawNested)
+import Control.Monad.Coroutine.SuspensionFunctors (Request, request,
+                                                   ReadRequest, requestRead,
+                                                   Reader, Reading(..), ReadingResult(..),
+                                                   weaveNestedReadWriteRequests)
+import Control.Monad.Coroutine.Nested (EitherFunctor(..), AncestorFunctor(..), liftAncestor)
 
-type SourceFunctor a x = EitherFunctor a (ParseRequest x)
-type SinkFunctor a x = EitherFunctor a (Request [x] [x])
+type SourceFunctor a x = EitherFunctor a (ReadRequest x)
+type SinkFunctor a x = EitherFunctor a (Request x x)
 
--- | A 'Sink' can be used to yield values from any nested `Coroutine` computation whose functor provably descends from
+-- | A 'Sink' can be used to yield output from any nested `Coroutine` computation whose functor provably descends from
 -- the functor /a/. It's the write-only end of a communication channel created by 'pipe'.
 newtype Sink (m :: * -> *) a x =
    Sink
    {
-   -- | This method puts a list of values into the `Sink`. The intervening 'Coroutine' computations suspend up to the
-   -- 'pipe' invocation that has created the argument sink. The method returns all values that could not make it into
-   -- the sink because of the sibling coroutine's death.
-   putChunk :: forall d. AncestorFunctor a d => [x] -> Coroutine d m [x]
+   -- | This method puts a portion of the producer's output into the `Sink`. The intervening 'Coroutine' computations
+   -- suspend up to the 'pipe' invocation that has created the argument sink. The method returns the suffix of the
+   -- argument that could not make it into the sink because of the sibling coroutine's death.
+   putChunk :: forall d. AncestorFunctor a d => x -> Coroutine d m x
    }
 
--- | A 'Source' can be used to read values into any nested `Coroutine` computation whose functor provably descends from
+-- | A 'Source' can be used to read input into any nested `Coroutine` computation whose functor provably descends from
 -- the functor /a/. It's the read-only end of a communication channel created by 'pipe'.
 newtype Source (m :: * -> *) a x =
    Source
    {
-   -- | This method gets a list of values from the 'Source', as well as an indication of the next value if any. The
-   -- first argument is a function that determines how many values should be consumed from the source. The function will
-   -- keep being called until it returns @False@ or the current chunk gets completely consumed. If the current chunk is
-   -- empty on call, a new one is obtained from the source. The intervening 'Coroutine' computations suspend all the way
-   -- to the 'pipe' function invocation that created the source.
-   foldChunk :: forall d p y. (AncestorFunctor a d, MonoidNull y) => 
-                Parser p [x] y -> Coroutine d m (y, Maybe (Parser p [x] y))
+   -- | This method consumes a portion of input from the 'Source' using the 'Reader' argument and returns the
+   -- 'ReadingResult'. Depending on the reader, the producer coroutine may not need to be resumed at all, or it may need
+   -- to be resumed many times. The intervening 'Coroutine' computations suspend all the way to the 'pipe' function
+   -- invocation that created the source.
+   readChunk :: forall d py y. AncestorFunctor a d => Reader x py y -> Coroutine d m (ReadingResult x py y)
    }
 
--- | A disconnected sink that ignores all values 'put' into it.
-nullSink :: forall m a x. Monad m => Sink m a x
-nullSink = Sink{putChunk= const (return [])}
+readAll :: Reader x x x
+readAll s = Advance readAll s s
 
--- | An empty source whose 'get' always returns Nothing.
-nullSource :: forall m a x. Monad m => Source m a x
-nullSource = Source{foldChunk= \p-> return (mempty, Just p)}
+-- | A disconnected sink that consumes and ignores all data 'put' into it.
+nullSink :: forall m a x. (Monad m, Monoid x) => Sink m a x
+nullSink = Sink{putChunk= const (return mempty)}
 
+-- | A disconnected sink that consumes and ignores all data 'put' into it.
+emptySource :: forall m a x. (Monad m, Monoid x) => Source m a x
+emptySource = Source{readChunk= return . finalize . ($ mempty)}
+   where finalize (Final _ x) = FinalResult x
+         finalize (Advance _ x _) = FinalResult x
+         finalize (Deferred _ x) = FinalResult x
+
 -- | Converts a 'Sink' on the ancestor functor /a/ into a sink on the descendant functor /d/.
 liftSink :: forall m a d x. (Monad m, AncestorFunctor a d) => Sink m a x -> Sink m d x
-liftSink s = Sink {putChunk= liftAncestor . (putChunk s :: [x] -> Coroutine d m [x])}
+liftSink s = Sink {putChunk= liftAncestor . (putChunk s :: x -> Coroutine d m x)}
+{-# INLINE liftSink #-}
 
 -- | Converts a 'Source' on the ancestor functor /a/ into a source on the descendant functor /d/.
 liftSource :: forall m a d x. (Monad m, AncestorFunctor a d) => Source m a x -> Source m d x
-liftSource s = Source {foldChunk= liftAncestor . (foldChunk s 
-                                                  :: forall p y. MonoidNull y => 
-                                                     Parser p [x] y -> Coroutine d m (y, Maybe (Parser p [x] y)))}
+liftSource s = Source {readChunk= liftAncestor . (readChunk s :: Reader x py y -> Coroutine d m (ReadingResult x py y))}
+{-# INLINE liftSource #-}
 
+-- | A sink mark-up transformation: every chunk going into the sink is accompanied by the given value.
+markUpWith :: forall m a x mark. (Monad m, Monoid x) => mark -> Sink m a [(x, mark)] -> Sink m a x
+markUpWith mark sink = Sink putMarkedChunk
+   where putMarkedChunk :: forall d. AncestorFunctor a d => x -> Coroutine d m x
+         putMarkedChunk x = do rest <- putChunk sink [(x, mark)]
+                               case rest of [] -> return mempty
+                                            [(y, _)]-> return y
+
+-- | A sink mark-down transformation: the marks get removed off each chunk.
+markDown :: forall m a x mark. (Monad m, MonoidNull x) => Sink m a x -> Sink m a [(x, mark)]
+markDown sink = Sink putUnmarkedChunk
+   where putUnmarkedChunk :: forall d. AncestorFunctor a d => [(x, mark)] -> Coroutine d m [(x, mark)]
+         putUnmarkedChunk [] = return mempty
+         putUnmarkedChunk ((x, mark):tail) = do rest <- putChunk sink x
+                                                if null rest 
+                                                   then putUnmarkedChunk tail
+                                                   else return ((rest, mark):tail)
+
 -- | The 'pipe' function splits the computation into two concurrent parts, /producer/ and /consumer/. The /producer/ is
 -- given a 'Sink' to put values into, and /consumer/ a 'Source' to get those values from. Once producer and consumer
 -- both complete, 'pipe' returns their paired results.
-pipe :: forall m a a1 a2 x r1 r2. (Monad m, Functor a, a1 ~ SinkFunctor a x, a2 ~ SourceFunctor a x) =>
+pipe :: forall m a a1 a2 x r1 r2. (Monad m, Monoid x, Functor a, a1 ~ SinkFunctor a x, a2 ~ SourceFunctor a x) =>
         (Sink m a1 x -> Coroutine a1 m r1) -> (Source m a2 x -> Coroutine a2 m r2) -> Coroutine a m (r1, r2)
 pipe = pipeG sequentialBinder
 
 -- | The 'pipeP' function is equivalent to 'pipe', except it runs the /producer/ and the /consumer/ in parallel.
 pipeP :: forall m a a1 a2 x r1 r2. 
-         (MonadParallel m, Functor a, a1 ~ SinkFunctor a x, a2 ~ SourceFunctor a x) =>
+         (MonadParallel m, Monoid x, Functor a, a1 ~ SinkFunctor a x, a2 ~ SourceFunctor a x) =>
          (Sink m a1 x -> Coroutine a1 m r1) -> (Source m a2 x -> Coroutine a2 m r2) -> Coroutine a m (r1, r2)
 pipeP = pipeG bindM2
 
 -- | A generic version of 'pipe'. The first argument is used to combine two computation steps.
-pipeG :: forall m a a1 a2 x r1 r2. (Monad m, Functor a, a1 ~ SinkFunctor a x, a2 ~ SourceFunctor a x) =>
+pipeG :: forall m a a1 a2 x r1 r2. (Monad m, Monoid x, Functor a, a1 ~ SinkFunctor a x, a2 ~ SourceFunctor a x) =>
          PairBinder m -> (Sink m a1 x -> Coroutine a1 m r1) -> (Source m a2 x -> Coroutine a2 m r2)
       -> Coroutine a m (r1, r2)
 pipeG run2 producer consumer =
-   liftM (uncurry (flip (,))) $ 
-   seesawNested run2 (nestedLazyParserRequestResolver) (consumer source) (producer sink)
-   where sink = Sink {putChunk= \xs-> if null xs then return []
-                                      else (liftAncestor (mapSuspension RightF (request xs) :: Coroutine a1 m [x]))}
-         source = Source {foldChunk= fc}
-         fc :: forall d p y. (AncestorFunctor a2 d, MonoidNull y) => 
-               Parser p [x] y -> Coroutine d m (y, Maybe (Parser p [x] y))
-         fc t = liftAncestor (mapSuspension RightF (requestParse t) :: Coroutine a2 m (y, Maybe (Parser p [x] y)))
+   liftM (uncurry (flip (,))) $
+   weave run2 weaveNestedReadWriteRequests (consumer source) (producer sink)
+   where sink = Sink {putChunk= \xs-> liftAncestor (mapSuspension RightF (request xs) :: Coroutine a1 m x)}
+         source = Source {readChunk= fc}
+         fc :: forall d py y. AncestorFunctor a2 d => Reader x py y -> Coroutine d m (ReadingResult x py y)
+         fc t = liftAncestor (mapSuspension RightF (requestRead t) :: Coroutine a2 m (ReadingResult x py y))
 
--- | Function 'get' tries to get a value from the given 'Source' argument. The intervening 'Coroutine' computations
--- suspend all the way to the 'pipe' function invocation that created the source. The function returns 'Nothing' if
--- the argument source is empty.
-get :: forall m a d x. (Monad m, AncestorFunctor a d) => Source m a x -> Coroutine d m (Maybe x)
-get source = foldChunk source anyToken
-             >>= \(r, _) -> return $ case r of [] -> Nothing
-                                               ~[x] -> Just x
+fromParser :: forall p x y. Monoid x => y -> Parser p x y -> Reader x (y -> y) y
+fromParser failure p s = case inspect (feed s p)
+                         of ([], Nothing) -> Final s failure
+                            ([], Just (Nothing, p')) -> Deferred (fromParser failure p') r'
+                               where (r', s') = case completeResults (feedEof p')
+                                                of [] -> (failure, s)
+                                                   hd:_ -> hd
+                            ([], Just (Just prefix, p')) -> Advance (fromParser failure p') (prefix r') prefix
+                               where (r', s'):_ = completeResults (feedEof p')
+                            ([(r, s')], Nothing) -> Final s' r
 
+-- | Function 'get' tries to get a single value from the given 'Source' argument. The intervening 'Coroutine'
+-- computations suspend all the way to the 'pipe' function invocation that created the source. The function returns
+-- 'Nothing' if the argument source is empty.
+get :: forall m a d x. (Monad m, AncestorFunctor a d) => Source m a [x] -> Coroutine d m (Maybe x)
+get source = readChunk source readOne
+              >>= \(FinalResult x) -> return x
+   where readOne [] = Deferred readOne Nothing
+         readOne (x:rest) = Final rest (Just x)
+
+-- | Tries to get a minimal, /i.e./, prime, prefix from the given 'Source' argument. The intervening 'Coroutine'
+-- computations suspend all the way to the 'pipe' function invocation that created the source. The function returns
+-- 'mempty' if the argument source is empty.
+getPrime :: forall m a d x. (Monad m, FactorialMonoid x, AncestorFunctor a d) => Source m a x -> Coroutine d m x
+getPrime source = readChunk source primeReader
+                  >>= \(FinalResult x) -> return x
+   where primeReader x = maybe (Deferred primeReader x) 
+                               (\(prefix, rest)-> Final rest prefix) 
+                               (splitPrimePrefix x)
+
+-- | Invokes its first argument with the value it gets from the source, if there is any to get.
+getWith :: forall m a d x. (Monad m, FactorialMonoid x, AncestorFunctor a d) =>
+           Source m a x -> (x -> Coroutine d m ()) -> Coroutine d m ()
+getWith source consumer = readChunk source primeReader
+                          >>= \(FinalResult x) -> x
+   where primeReader x = maybe (Deferred primeReader (return ()))
+                               (\(prefix, rest)-> Final rest (consumer prefix) )
+                               (splitPrimePrefix x)
+
 -- | Function 'peek' acts the same way as 'get', but doesn't actually consume the value from the source; sequential
 -- calls to 'peek' will always return the same value.
-peek :: forall m a d x. (Monad m, AncestorFunctor a d) => Source m a x -> Coroutine d m (Maybe x)
-peek source = foldChunk source (lookAhead anyToken)
-             >>= \(r, _) -> return $ case r of [] -> Nothing
-                                               ~[x] -> Just x
+peek :: forall m a d x. (Monad m, AncestorFunctor a d) => Source m a [x] -> Coroutine d m (Maybe x)
+peek source = readChunk source readOneAhead
+              >>= \(FinalResult x) -> return x
+   where readOneAhead [] = Deferred readOneAhead Nothing
+         readOneAhead s@(x:_) = Final s (Just x)
 
--- | 'getList' returns the list of all values generated by the source.
-getList :: forall m a d x. (Monad m, AncestorFunctor a d) => Source m a x -> Coroutine d m [x]
-getList = getTicked acceptAll
+-- | 'getAll' consumes and returns all data generated by the source.
+getAll :: forall m a d x. (Monad m, Monoid x, AncestorFunctor a d) => Source m a x -> Coroutine d m x
+getAll source = readChunk source (readAll id)
+                >>= \(FinalResult all)-> return all
+   where readAll :: (x -> x) -> Reader x () x
+         readAll prefix s = Deferred (readAll (prefix . mappend s)) (prefix s)
 
--- | Invokes its first argument with the value it gets from the source, if there is any to get.
-getWith :: forall m a d x. (Monad m, AncestorFunctor a d) => (x -> Coroutine d m ()) -> Source m a x -> Coroutine d m ()
-getWith consumer source = get source >>= maybe (return ()) consumer
+-- | Consumes inputs from the /source/ as long as the /parser/ accepts it.
+getParsed :: forall m a d p x y. (Monad m, Monoid x, Monoid y, AncestorFunctor a d) => 
+             Parser p x y -> Source m a x -> Coroutine d m y
+getParsed parser = getRead (fromParser mempty parser)
 
--- | Consumes values from the /source/ as long as the /parser/ accepts them.
-getTicked :: forall m p a d x. (Monad m, AncestorFunctor a d) => Parser p [x] [x] -> Source m a x -> Coroutine d m [x]
-getTicked parser source = loop return parser
-   where loop cont p = foldChunk source p >>= proceed cont
-         proceed cont (chunk, Nothing) = cont chunk
-         proceed cont (chunk, Just p') = loop (cont . (chunk ++)) p'
+-- | Consumes input from the /source/ as long as the /reader/ accepts it.
+getRead :: forall m a d x y. (Monad m, Monoid x, AncestorFunctor a d) => 
+           Reader x (y -> y) y -> Source m a x -> Coroutine d m y
+getRead reader source = loop return reader
+   where loop cont r = readChunk source r >>= proceed cont
+         proceed cont (FinalResult chunk) = cont chunk
+         proceed cont (ResultPart d p') = loop (cont . d) p'
 
 -- | Consumes values from the /source/ as long as each satisfies the predicate, then returns their list.
-getWhile :: forall m a d x. (Monad m, AncestorFunctor a d) => (x -> Bool) -> Source m a x -> Coroutine d m [x]
-getWhile predicate = getTicked (takeWhile (predicate . head))
+getWhile :: forall m a d x. (Monad m, FactorialMonoid x, AncestorFunctor a d) =>
+            (x -> Bool) -> Source m a x -> Coroutine d m x
+getWhile predicate source = readChunk source (readWhile predicate id)
+                            >>= \(FinalResult x)-> return x
+   where readWhile :: (x -> Bool) -> (x -> x) -> Reader x () x
+         readWhile predicate prefix1 s = if null suffix
+                                         then Deferred (readWhile predicate (prefix1 . mappend s)) (prefix1 s)
+                                         else Final suffix (prefix1 prefix2)
+            where (prefix2, suffix) = span predicate s
 
 -- | Consumes values from the /source/ until one of them satisfies the predicate or the source is emptied, then returns
 -- the pair of the list of preceding values and maybe the one value that satisfied the predicate. The latter is not
 -- consumed.
-getUntil :: forall m a d x. (Monad m, AncestorFunctor a d) => 
-            (x -> Bool) -> Source m a x -> Coroutine d m ([x], Maybe x)
-getUntil f source = loop id
-   where loop cont = foldChunk source (takeWhile (not . f . head)
-                                       `andThen` lookAhead (fmap (First . Just . head) anyToken 
-                                                            <<|> return (First Nothing)))
-                     >>= extract cont
-         extract cont ((chunk, First mx), Nothing) = return (cont chunk, mx)
-         extract cont ((chunk, First Nothing), Just{}) = loop (cont . (chunk ++))
+getUntil :: forall m a d x. (Monad m, FactorialMonoid x, AncestorFunctor a d) =>
+            (x -> Bool) -> Source m a x -> Coroutine d m (x, Maybe x)
+getUntil predicate source = readChunk source (readUntil (not . predicate) id)
+                            >>= \(FinalResult r)-> return r
+   where readUntil :: (x -> Bool) -> (x -> x) -> Reader x () (x, Maybe x)
+         readUntil predicate prefix1 s = if null suffix
+                                         then Deferred (readUntil predicate (prefix1 . mappend s)) (prefix1 s, Nothing)
+                                         else Final suffix (prefix1 prefix2, Just $ primePrefix suffix)
+            where (prefix2, suffix) = span predicate s
 
--- | Copies all data from the /source/ argument into the /sink/ argument.
-pour :: forall m a1 a2 d x . (Monad m, AncestorFunctor a1 d, AncestorFunctor a2 d)
+-- | Copies all data from the /source/ argument into the /sink/ argument. The result indicates if there was any chunk to
+-- copy.
+pour :: forall m a1 a2 d x . (Monad m, Monoid x, AncestorFunctor a1 d, AncestorFunctor a2 d)
+        => Source m a1 x -> Sink m a2 x -> Coroutine d m Bool
+pour source sink = loop False
+   where loop another = readChunk source readAll >>= extract another
+         extract another (FinalResult _chunk) = return another -- the last chunk must be empty
+         extract _ (ResultPart chunk _) = putChunk sink chunk >> loop True
+
+-- | Copies all data from the /source/ argument into the /sink/ argument, like 'pour' but ignoring the result.
+pour_ :: forall m a1 a2 d x . (Monad m, Monoid x, AncestorFunctor a1 d, AncestorFunctor a2 d)
         => Source m a1 x -> Sink m a2 x -> Coroutine d m ()
-pour source sink = loop
-   where loop = getChunk source >>= nullOrElse (return ()) ((>> loop) . putChunk sink)
+pour_ source sink = pour source sink >> return ()
 
 -- | Like 'pour', copies data from the /source/ to the /sink/, but only as long as it satisfies the predicate.
-pourTicked :: forall m p a1 a2 d x . (Monad m, AncestorFunctor a1 d, AncestorFunctor a2 d)
-              => Parser p [x] [x] -> Source m a1 x -> Sink m a2 x -> Coroutine d m ()
-pourTicked parser source sink = loop parser
-   where loop p = foldChunk source p
-                  >>= \(chunk, p')-> unless (null chunk) (putChunk sink chunk >> maybe (return ()) loop p')
+pourRead :: forall m a1 a2 d x y. (Monad m, MonoidNull x, MonoidNull y, AncestorFunctor a1 d, AncestorFunctor a2 d)
+              => Reader x y y -> Source m a1 x -> Sink m a2 y -> Coroutine d m ()
+pourRead reader source sink = loop reader
+   where loop p = readChunk source p >>= extract
+         extract (FinalResult r) = unless (null r) (putChunk sink r >> return ())
+         extract (ResultPart chunk p') = putChunk sink chunk >> loop p'
 
 -- | Parses the input data using the given parser and copies the results to output.
-pourParsed :: forall m p a1 a2 d x y. (Monad m, AncestorFunctor a1 d, AncestorFunctor a2 d)
-              => Parser p [x] [y] -> Source m a1 x -> Sink m a2 y -> Coroutine d m ()
-pourParsed parser source sink = loop parser
-   where loop p = foldChunk source p
-                  >>= \(chunk, p')-> unless (null chunk) (putChunk sink chunk >> maybe (return ()) loop p')
+pourParsed :: forall m p a1 a2 d x y. (Monad m, MonoidNull x, MonoidNull y, AncestorFunctor a1 d, AncestorFunctor a2 d)
+              => Parser p x y -> Source m a1 x -> Sink m a2 y -> Coroutine d m ()
+pourParsed parser source sink = loop (fromParser mempty parser)
+   where loop p = readChunk source p >>= extract
+         extract (FinalResult r) = unless (null r) (putChunk sink r >> return ())
+         extract (ResultPart d p') = putChunk sink (d mempty) >> loop p'
 
 -- | Like 'pour', copies data from the /source/ to the /sink/, but only as long as it satisfies the predicate.
-pourWhile :: forall m a1 a2 d x . (Monad m, AncestorFunctor a1 d, AncestorFunctor a2 d)
+pourWhile :: forall m a1 a2 d x . (Monad m, FactorialMonoid x, AncestorFunctor a1 d, AncestorFunctor a2 d)
              => (x -> Bool) -> Source m a1 x -> Sink m a2 x -> Coroutine d m ()
-pourWhile f = pourTicked (takeWhile (f . head))
+pourWhile = pourRead . readWhile
+   where readWhile :: FactorialMonoid x => (x -> Bool) -> Reader x x x
+         readWhile p = while
+            where while s = if null suffix
+                            then Advance while prefix prefix
+                            else Final suffix prefix
+                     where (prefix, suffix) = span p s
 
 -- | Like 'pour', copies data from the /source/ to the /sink/, but only until one value satisfies the predicate. That
 -- value is returned rather than copied.
-pourUntil :: forall m a1 a2 d x . (Monad m, AncestorFunctor a1 d, AncestorFunctor a2 d)
+pourUntil :: forall m a1 a2 d x . (Monad m, FactorialMonoid x, AncestorFunctor a1 d, AncestorFunctor a2 d)
              => (x -> Bool) -> Source m a1 x -> Sink m a2 x -> Coroutine d m (Maybe x)
-pourUntil f source sink = loop
-   where loop = foldChunk source (takeWhile (not . f . head)
-                                  `andThen` lookAhead (fmap (First . Just . head) anyToken 
-                                                       <<|> return (First Nothing)))
-                >>= extract
-         extract ((chunk, First mx), Nothing) = putList chunk sink >> return mx
-         extract ((chunk, First Nothing), Just{}) = putChunk sink chunk >> loop
+pourUntil predicate source sink = loop $ readUntil (not . predicate)
+   where readUntil :: FactorialMonoid x => (x -> Bool) -> Reader x x (x, Maybe x)
+         readUntil p = until
+            where until s = if null suffix
+                            then Advance until (prefix, Nothing) prefix
+                            else Final suffix (prefix, Just $ primePrefix suffix)
+                     where (prefix, suffix) = span p s
+         loop rd = readChunk source rd >>= extract
+         extract (FinalResult (chunk, mx)) = putChunk sink chunk >> return mx
+         extract (ResultPart chunk rd') = putChunk sink chunk >> loop rd'
 
 -- | 'mapStream' is like 'pour' that applies the function /f/ to each argument before passing it into the /sink/.
-mapStream :: forall m a1 a2 d x y . (Monad m, AncestorFunctor a1 d, AncestorFunctor a2 d)
+mapStream :: forall m a1 a2 d x y . (Monad m, FactorialMonoid x, Monoid y, AncestorFunctor a1 d, AncestorFunctor a2 d)
            => (x -> y) -> Source m a1 x -> Sink m a2 y -> Coroutine d m ()
 mapStream f source sink = loop
-   where loop = getChunk source >>= nullOrElse (return ()) ((>> loop) . putChunk sink . map f)
+   where loop = readChunk source readAll
+                >>= \r-> case r
+                         of ResultPart chunk _ -> putChunk sink (map f chunk) >> loop
+                            FinalResult _ -> return ()  -- the last chunk must be empty
 
 -- | An equivalent of 'Data.List.map' that works on a 'Sink' instead of a list. The argument function is applied to
 -- every value vefore it's written to the sink argument.
-mapSink :: forall m a x y. Monad m => (x -> y) -> Sink m a y -> Sink m a x
-mapSink f sink = Sink{putChunk= \xs-> putChunk sink (map f xs) 
+mapSink :: forall m a x y. Monad m => (x -> y) -> Sink m a [y] -> Sink m a [x]
+mapSink f sink = Sink{putChunk= \xs-> putChunk sink (List.map f xs)
                                       >>= \rest-> return (dropExcept (length rest) xs)}
    where dropExcept :: forall z. Int -> [z] -> [z]
          dropExcept 0 _ = []
@@ -269,26 +360,25 @@
 
 -- | 'mapMaybeStream' is to 'mapStream' like 'Data.Maybe.mapMaybe' is to 'Data.List.map'.
 mapMaybeStream :: forall m a1 a2 d x y . (Monad m, AncestorFunctor a1 d, AncestorFunctor a2 d)
-                => (x -> Maybe y) -> Source m a1 x -> Sink m a2 y -> Coroutine d m ()
+                => (x -> Maybe y) -> Source m a1 [x] -> Sink m a2 [y] -> Coroutine d m ()
 mapMaybeStream f source sink = mapMStreamChunks_ ((>> return ()) . putChunk sink . mapMaybe f) source
 
 -- | 'concatMapStream' is to 'mapStream' like 'Data.List.concatMap' is to 'Data.List.map'.
-concatMapStream :: forall m a1 a2 d x y . (Monad m, AncestorFunctor a1 d, AncestorFunctor a2 d)
-                   => (x -> [y]) -> Source m a1 x -> Sink m a2 y -> Coroutine d m ()
-concatMapStream f source sink = loop
-   where loop = getChunk source >>= nullOrElse (return ()) ((>> loop) . putChunk sink . concatMap f)
+concatMapStream :: forall m a1 a2 d x y . (Monad m, Monoid y, AncestorFunctor a1 d, AncestorFunctor a2 d)
+                   => (x -> y) -> Source m a1 [x] -> Sink m a2 y -> Coroutine d m ()
+concatMapStream f = mapStream (mconcat . List.map f)
 
 -- | 'mapAccumStream' is similar to 'mapAccumL' except it reads the values from a 'Source' instead of a list
 -- and writes the mapped values into a 'Sink' instead of returning another list.
 mapAccumStream :: forall m a1 a2 d x y acc . (Monad m, AncestorFunctor a1 d, AncestorFunctor a2 d)
-                  => (acc -> x -> (acc, y)) -> acc -> Source m a1 x -> Sink m a2 y -> Coroutine d m acc
+                  => (acc -> x -> (acc, y)) -> acc -> Source m a1 [x] -> Sink m a2 [y] -> Coroutine d m acc
 mapAccumStream f acc source sink = foldMStreamChunks (\a xs-> dispatch $ mapAccumL f a xs) acc source
    where dispatch (a, ys) = putChunk sink ys >> return a
 
 -- | 'concatMapAccumStream' is a love child of 'concatMapStream' and 'mapAccumStream': it threads the accumulator like
 -- the latter, but its argument function returns not a single value, but a list of values to write into the sink.
 concatMapAccumStream :: forall m a1 a2 d x y acc . (Monad m, AncestorFunctor a1 d, AncestorFunctor a2 d)
-                  => (acc -> x -> (acc, [y])) -> acc -> Source m a1 x -> Sink m a2 y -> Coroutine d m acc
+                  => (acc -> x -> (acc, [y])) -> acc -> Source m a1 [x] -> Sink m a2 [y] -> Coroutine d m acc
 concatMapAccumStream f acc source sink = foldMStreamChunks (\a xs-> dispatch $ concatMapAccumL a xs) acc source
    where dispatch (a, ys) = putChunk sink ys >> return a
          concatMapAccumL s []        =  (s, [])
@@ -297,92 +387,120 @@
                   (s'', ys) = concatMapAccumL s' xs
 
 -- | Like 'mapStream' except it runs the argument function on whole chunks read from the input.
-mapStreamChunks :: forall m a1 a2 d x y . (Monad m, AncestorFunctor a1 d, AncestorFunctor a2 d)
-                   => ([x] -> [y]) -> Source m a1 x -> Sink m a2 y -> Coroutine d m ()
+mapStreamChunks :: forall m a1 a2 d x y . (Monad m, Monoid x, AncestorFunctor a1 d, AncestorFunctor a2 d)
+                   => (x -> y) -> Source m a1 x -> Sink m a2 y -> Coroutine d m ()
 mapStreamChunks f source sink = loop
-   where loop = getChunk source >>= nullOrElse (return ()) ((>> loop) . flip putList sink . f)
+   where loop = readChunk source readAll
+                >>= \r-> case r
+                         of ResultPart chunk _ -> putChunk sink (f chunk) >> loop
+                            FinalResult _ -> return ()  -- the last chunk must be empty
 
+-- | Like 'mapAccumStream' except it runs the argument function on whole chunks read from the input.
+mapAccumStreamChunks :: forall m a1 a2 d x y acc. (Monad m, Monoid x, AncestorFunctor a1 d, AncestorFunctor a2 d)
+                   => (acc -> x -> (acc, y)) -> acc -> Source m a1 x -> Sink m a2 y -> Coroutine d m acc
+mapAccumStreamChunks f acc source sink = loop acc
+   where loop acc = readChunk source readAll
+                    >>= \r-> case r
+                             of ResultPart chunk _ -> let (acc', chunk') = f acc chunk 
+                                                      in putChunk sink chunk' >> loop acc'
+                                FinalResult _ -> return acc  -- the last chunk must be empty
+
 -- | 'mapMStream' is similar to 'Control.Monad.mapM'. It draws the values from a 'Source' instead of a list, writes the
 -- mapped values to a 'Sink', and returns a 'Coroutine'.
-mapMStream :: forall m a1 a2 d x y . (Monad m, AncestorFunctor a1 d, AncestorFunctor a2 d)
+mapMStream :: forall m a1 a2 d x y . (Monad m, FactorialMonoid x, Monoid y, AncestorFunctor a1 d, AncestorFunctor a2 d)
               => (x -> Coroutine d m y) -> Source m a1 x -> Sink m a2 y -> Coroutine d m ()
 mapMStream f source sink = loop
-   where loop = getChunk source >>= nullOrElse (return ()) ((>> loop) . (putChunk sink =<<) . mapM f)
+   where loop = readChunk source readAll
+                >>= \r-> case r
+                         of ResultPart chunk _ -> mapM f chunk >>= putChunk sink >> loop
+                            FinalResult _ -> return ()  -- the last chunk must be empty
 
 -- | 'mapMStream_' is similar to 'Control.Monad.mapM_' except it draws the values from a 'Source' instead of a list and
 -- works with 'Coroutine' instead of an arbitrary monad.
-mapMStream_ :: forall m a d x . (Monad m, AncestorFunctor a d)
-              => (x -> Coroutine d m ()) -> Source m a x -> Coroutine d m ()
-mapMStream_ f = mapMStreamChunks_ (Control.Monad.mapM_ f)
+mapMStream_ :: forall m a d x r. (Monad m, FactorialMonoid x, AncestorFunctor a d)
+              => (x -> Coroutine d m r) -> Source m a x -> Coroutine d m ()
+mapMStream_ f = mapMStreamChunks_ (mapM_ f)
 
 -- | Like 'mapMStream_' except it runs the argument function on whole chunks read from the input.
-mapMStreamChunks_ :: forall m a d x . (Monad m, AncestorFunctor a d)
-              => ([x] -> Coroutine d m ()) -> Source m a x -> Coroutine d m ()
+mapMStreamChunks_ :: forall m a d x r. (Monad m, Monoid x, AncestorFunctor a d)
+              => (x -> Coroutine d m r) -> Source m a x -> Coroutine d m ()
 mapMStreamChunks_ f source = loop
-   where loop = getChunk source >>= nullOrElse (return ()) ((>> loop) . f)
+   where loop = readChunk source readAll
+                >>= \r-> case r
+                         of ResultPart chunk _ -> f chunk >> loop
+                            FinalResult _ -> return ()  -- the last chunk must be empty
 
 -- | An equivalent of 'Control.Monad.filterM'. Draws the values from a 'Source' instead of a list, writes the filtered
 -- values to a 'Sink', and returns a 'Coroutine'.
-filterMStream :: forall m a1 a2 d x . (Monad m, AncestorFunctor a1 d, AncestorFunctor a2 d)
+filterMStream :: forall m a1 a2 d x . (Monad m, FactorialMonoid x, AncestorFunctor a1 d, AncestorFunctor a2 d)
               => (x -> Coroutine d m Bool) -> Source m a1 x -> Sink m a2 x -> Coroutine d m ()
-filterMStream f source sink = mapMStream_ (\x-> f x >>= flip when (put sink x)) source
+filterMStream f = mapMStream (\x-> f x >>= \p-> return $ if p then x else mempty)
 
 -- | Similar to 'Data.List.foldl', but reads the values from a 'Source' instead of a list.
-foldStream :: forall m a d x acc . (Monad m, AncestorFunctor a d)
+foldStream :: forall m a d x acc . (Monad m, FactorialMonoid x, AncestorFunctor a d)
               => (acc -> x -> acc) -> acc -> Source m a x -> Coroutine d m acc
 foldStream f acc source = loop acc
-   where loop s = getChunk source >>= nullOrElse (return s) (loop . foldl f s)
+   where loop a = readChunk source readAll
+                  >>= \r-> case r
+                           of ResultPart chunk _ -> loop (foldl f a chunk)
+                              FinalResult{} -> return a  -- the last chunk must be empty
 
 -- | 'foldMStream' is similar to 'Control.Monad.foldM' except it draws the values from a 'Source' instead of a list and
 -- works with 'Coroutine' instead of an arbitrary monad.
 foldMStream :: forall m a d x acc . (Monad m, AncestorFunctor a d)
-              => (acc -> x -> Coroutine d m acc) -> acc -> Source m a x -> Coroutine d m acc
+              => (acc -> x -> Coroutine d m acc) -> acc -> Source m a [x] -> Coroutine d m acc
 foldMStream f acc source = loop acc
-   where loop a = getChunk source >>= nullOrElse (return a) ((loop =<<) . foldM f a)
+   where loop a = readChunk source readAll
+                  >>= \r-> case r
+                           of ResultPart chunk _ -> foldM f a chunk >>= loop
+                              FinalResult [] -> return a  -- the last chunk must be empty
 
 -- | A variant of 'foldMStream' that discards the final result value.
 foldMStream_ :: forall m a d x acc . (Monad m, AncestorFunctor a d)
-                => (acc -> x -> Coroutine d m acc) -> acc -> Source m a x -> Coroutine d m ()
+                => (acc -> x -> Coroutine d m acc) -> acc -> Source m a [x] -> Coroutine d m ()
 foldMStream_ f acc source = foldMStream f acc source >> return ()
 
 -- | Like 'foldMStream' but working on whole chunks from the argument source.
-foldMStreamChunks :: forall m a d x acc . (Monad m, AncestorFunctor a d)
-                     => (acc -> [x] -> Coroutine d m acc) -> acc -> Source m a x -> Coroutine d m acc
+foldMStreamChunks :: forall m a d x acc . (Monad m, Monoid x, AncestorFunctor a d)
+                     => (acc -> x -> Coroutine d m acc) -> acc -> Source m a x -> Coroutine d m acc
 foldMStreamChunks f acc source = loop acc
-   where loop a = getChunk source >>= nullOrElse (return a) ((loop =<<) . f a)
+   where loop a = readChunk source readAll
+                  >>= \r-> case r
+                           of ResultPart chunk _ -> f a chunk >>= loop
+                              FinalResult _ -> return a  -- the last chunk must be empty
 
 -- | 'unfoldMStream' is a version of 'Data.List.unfoldr' that writes the generated values into a 'Sink' instead of
 -- returning a list.
 unfoldMStream :: forall m a d x acc . (Monad m, AncestorFunctor a d)
-                 => (acc -> Coroutine d m (Maybe (x, acc))) -> acc -> Sink m a x -> Coroutine d m acc
+                 => (acc -> Coroutine d m (Maybe (x, acc))) -> acc -> Sink m a [x] -> Coroutine d m acc
 unfoldMStream f acc sink = loop acc
    where loop a = f a >>= maybe (return a) (\(x, acc')-> put sink x >> loop acc')
 
 -- | 'unmapMStream_' is opposite of 'mapMStream_'; it takes a 'Sink' instead of a 'Source' argument and writes the
 -- generated values into it.
 unmapMStream_ :: forall m a d x . (Monad m, AncestorFunctor a d)
-                 => Coroutine d m (Maybe x) -> Sink m a x -> Coroutine d m ()
+                 => Coroutine d m (Maybe x) -> Sink m a [x] -> Coroutine d m ()
 unmapMStream_ f sink = loop
    where loop = f >>= maybe (return ()) (\x-> put sink x >> loop)
 
 -- | Like 'unmapMStream_' but writing whole chunks of generated data into the argument sink.
-unmapMStreamChunks_ :: forall m a d x . (Monad m, AncestorFunctor a d)
-                       => Coroutine d m [x] -> Sink m a x -> Coroutine d m ()
+unmapMStreamChunks_ :: forall m a d x . (Monad m, MonoidNull x, AncestorFunctor a d)
+                       => Coroutine d m x -> Sink m a x -> Coroutine d m ()
 unmapMStreamChunks_ f sink = loop >> return ()
-   where loop = f >>= nullOrElse (return []) ((>>= nullOrElse loop return) . putChunk sink)
+   where loop = f >>= nullOrElse (return mempty) ((>>= nullOrElse loop return) . putChunk sink)
 
 -- | Equivalent to 'Data.List.partition'. Takes a 'Source' instead of a list argument and partitions its contents into
 -- the two 'Sink' arguments.
 partitionStream :: forall m a1 a2 a3 d x . (Monad m, AncestorFunctor a1 d, AncestorFunctor a2 d, AncestorFunctor a3 d)
-                   => (x -> Bool) -> Source m a1 x -> Sink m a2 x -> Sink m a3 x -> Coroutine d m ()
+                   => (x -> Bool) -> Source m a1 [x] -> Sink m a2 [x] -> Sink m a3 [x] -> Coroutine d m ()
 partitionStream f source true false = mapMStreamChunks_ partitionChunk source
    where partitionChunk (x:rest) = partitionTo (f x) x rest
-         partitionChunk [] = error "Chunks cannot be empty!"
+         partitionChunk [] = return ()
          partitionTo False x chunk = let (falses, rest) = break f chunk
                                      in putChunk false (x:falses)
                                         >> case rest of y:ys -> partitionTo True y ys
                                                         [] -> return ()
-         partitionTo True x chunk = let (trues, rest) = span f chunk
+         partitionTo True x chunk = let (trues, rest) = List.span f chunk
                                     in putChunk true (x:trues)
                                        >> case rest of y:ys -> partitionTo False y ys
                                                        [] -> return ()
@@ -390,7 +508,8 @@
 -- | 'zipWithMStream' is similar to 'Control.Monad.zipWithM' except it draws the values from two 'Source' arguments
 -- instead of two lists, sends the results into a 'Sink', and works with 'Coroutine' instead of an arbitrary monad.
 zipWithMStream :: forall m a1 a2 a3 d x y z. (Monad m, AncestorFunctor a1 d, AncestorFunctor a2 d, AncestorFunctor a3 d)
-                  => (x -> y -> Coroutine d m z) -> Source m a1 x -> Source m a2 y -> Sink m a3 z -> Coroutine d m ()
+                  => (x -> y -> Coroutine d m z) -> Source m a1 [x] -> Source m a2 [y] -> Sink m a3 [z]
+                  -> Coroutine d m ()
 zipWithMStream f source1 source2 sink = loop
    where loop = do mx <- get source1
                    my <- get source2
@@ -400,7 +519,8 @@
 -- | 'parZipWithMStream' is equivalent to 'zipWithMStream', but it consumes the two sources in parallel.
 parZipWithMStream :: forall m a1 a2 a3 d x y z.
                      (MonadParallel m, AncestorFunctor a1 d, AncestorFunctor a2 d, AncestorFunctor a3 d)
-                     => (x -> y -> Coroutine d m z) -> Source m a1 x -> Source m a2 y -> Sink m a3 z -> Coroutine d m ()
+                     => (x -> y -> Coroutine d m z) -> Source m a1 [x] -> Source m a2 [y] -> Sink m a3 [z]
+                     -> Coroutine d m ()
 parZipWithMStream f source1 source2 sink = loop
    where loop = bindM2 zipMaybe (get source1) (get source2)
          zipMaybe (Just x) (Just y) = f x y >>= put sink >> loop
@@ -408,11 +528,13 @@
 
 -- | 'tee' is similar to 'pour' except it distributes every input value from its source argument into its both sink
 -- arguments.
-tee :: forall m a1 a2 a3 d x . (Monad m, AncestorFunctor a1 d, AncestorFunctor a2 d, AncestorFunctor a3 d)
+tee :: forall m a1 a2 a3 d x . (Monad m, Monoid x, AncestorFunctor a1 d, AncestorFunctor a2 d, AncestorFunctor a3 d)
        => Source m a1 x -> Sink m a2 x -> Sink m a3 x -> Coroutine d m ()
 tee source sink1 sink2 = distribute
-   where distribute = getChunk source
-                      >>= nullOrElse (return ()) (\x-> putChunk sink1 x >> putChunk sink2 x >> distribute)
+   where distribute = readChunk source readAll
+                      >>= \r-> case r
+                               of ResultPart chunk _ -> putChunk sink1 chunk >> putChunk sink2 chunk >> distribute
+                                  FinalResult _ -> return ()  -- the last chunk must be empty
 
 -- | Every value 'put' into a 'teeSink' result sink goes into its both argument sinks: @put (teeSink s1 s2) x@ is
 -- equivalent to @put s1 x >> put s2 x@. The 'putChunk' method returns the list of values that couldn't fit into the
@@ -420,7 +542,7 @@
 teeSink :: forall m a1 a2 a3 x . (Monad m, AncestorFunctor a1 a3, AncestorFunctor a2 a3)
            => Sink m a1 x -> Sink m a2 x -> Sink m a3 x
 teeSink s1 s2 = Sink{putChunk= teeChunk}
-   where teeChunk :: forall d. AncestorFunctor a3 d => [x] -> Coroutine d m [x]
+   where teeChunk :: forall d. AncestorFunctor a3 d => x -> Coroutine d m x
          teeChunk x = putChunk s1' x >> putChunk s2' x
          s1' :: Sink m a3 x
          s1' = liftSink s1
@@ -429,25 +551,18 @@
 
 -- | This function puts a value into the given `Sink`. The intervening 'Coroutine' computations suspend up
 -- to the 'pipe' invocation that has created the argument sink.
-put :: forall m a d x. (Monad m, AncestorFunctor a d) => Sink m a x -> x -> Coroutine d m ()
+put :: forall m a d x. (Monad m, AncestorFunctor a d) => Sink m a [x] -> x -> Coroutine d m ()
 put sink x = putChunk sink [x] >> return ()
 
 -- | Like 'put', but returns a Bool that determines if the sink is still active.
-tryPut :: forall m a d x. (Monad m, AncestorFunctor a d) => Sink m a x -> x -> Coroutine d m Bool
+tryPut :: forall m a d x. (Monad m, AncestorFunctor a d) => Sink m a [x] -> x -> Coroutine d m Bool
 tryPut sink x = liftM null $ putChunk sink [x]
 
--- | 'putList' puts an entire list into its /sink/ argument. If the coroutine fed by the /sink/ dies, the remainder of
+-- | 'putAll' puts an entire list into its /sink/ argument. If the coroutine fed by the /sink/ dies, the remainder of
 -- the argument list is returned.
-putList :: forall m a d x. (Monad m, AncestorFunctor a d) => [x] -> Sink m a x -> Coroutine d m [x]
-putList l sink = if null l then return [] else putChunk sink l
-
-getChunk :: forall m a d x. (Monad m, AncestorFunctor a d) => Source m a x -> Coroutine d m [x]
-getChunk source = liftM fst $ foldChunk source acceptAll
-
--- | Like 'putList', except it puts the contents of the given 'Data.Sequence.Seq' into the sink.
-putQueue :: forall m a d x. (Monad m, AncestorFunctor a d) => Seq x -> Sink m a x -> Coroutine d m [x]
-putQueue q sink = putList (toList (viewl q)) sink
+putAll :: forall m a d x. (Monad m, MonoidNull x, AncestorFunctor a d) => x -> Sink m a x -> Coroutine d m x
+putAll l sink = if null l then return l else putChunk sink l
 
-nullOrElse :: a -> ([x] -> a) -> [x] -> a
-nullOrElse nullCase _ [] = nullCase
-nullOrElse _ f list = f list
+nullOrElse :: MonoidNull x => a -> (x -> a) -> x -> a
+nullOrElse nullCase f x | null x = nullCase
+                        | otherwise = f x
diff --git a/Control/Concurrent/SCC/Types.hs b/Control/Concurrent/SCC/Types.hs
--- a/Control/Concurrent/SCC/Types.hs
+++ b/Control/Concurrent/SCC/Types.hs
@@ -1,5 +1,5 @@
 {- 
-    Copyright 2009-2010 Mario Blazevic
+    Copyright 2009-2013 Mario Blazevic
 
     This file is part of the Streaming Component Combinators (SCC) project.
 
@@ -18,13 +18,13 @@
 -- 'Control.Concurrent.SCC.Streams.Sink' and 'Control.Concurrent.SCC.Streams.Source' values. The simplest of the bunch
 -- are 'Consumer' and 'Producer' types, which respectively operate on a single source or sink. A 'Transducer' has access
 -- both to a 'Control.Concurrent.SCC.Streams.Source' to read from and a 'Control.Concurrent.SCC.Streams.Sink' to write
--- into. Finally, a 'Splitter' reads from a single source and writes all input into two sinks of the same type,
--- signalling interesting input boundaries by writing into the third sink.
+-- into. Finally, a 'Splitter' reads from a single source and writes all of the input, without any modifications, into
+-- two sinks of the same type.
 -- 
 
 {-# LANGUAGE ScopedTypeVariables, KindSignatures, RankNTypes,
-             MultiParamTypeClasses, FlexibleContexts, FlexibleInstances, FunctionalDependencies, TypeFamilies #-}
-{-# OPTIONS_HADDOCK hide #-}
+             MultiParamTypeClasses, FlexibleContexts, FlexibleInstances, OverlappingInstances,
+             FunctionalDependencies, TypeFamilies #-}
 
 module Control.Concurrent.SCC.Types (
    -- * Component types
@@ -32,28 +32,32 @@
    OpenConsumer, Consumer(..), OpenProducer, Producer(..),
    OpenTransducer, Transducer(..), OpenSplitter, Splitter(..),
    Boundary(..), Markup(..), Parser,
-   Branching (combineBranches),
+   PipeableComponentPair (compose), Branching (combineBranches),
    -- * Component constructors
    isolateConsumer, isolateProducer, isolateTransducer, isolateSplitter,
-   oneToOneTransducer, statelessTransducer, statefulTransducer,
+   oneToOneTransducer, statelessTransducer, statelessChunkTransducer, statefulTransducer,
    statelessSplitter, statefulSplitter,
    )
 where
 
-import Control.Category (Category(..))
+import Control.Category (Category(id), (>>>))
 import qualified Control.Category as Category
+import Control.Monad (liftM)
+import Data.Monoid (Monoid(..))
 
 import Control.Monad.Coroutine
+import Data.Monoid.Null (MonoidNull)
+import Data.Monoid.Factorial (FactorialMonoid)
 
 import Control.Concurrent.SCC.Streams
 
-type OpenConsumer m a d x r = AncestorFunctor a d => Source m a x -> Coroutine d m r
-type OpenProducer m a d x r = AncestorFunctor a d => Sink m a x -> Coroutine d m r
+type OpenConsumer m a d x r = (AncestorFunctor a d, Monoid x) => Source m a x -> Coroutine d m r
+type OpenProducer m a d x r = (AncestorFunctor a d, Monoid x) => Sink m a x -> Coroutine d m r
 type OpenTransducer m a1 a2 d x y r = 
-   (AncestorFunctor a1 d, AncestorFunctor a2 d) => Source m a1 x -> Sink m a2 y -> Coroutine d m r
-type OpenSplitter m a1 a2 a3 a4 d x b r =
-   (AncestorFunctor a1 d, AncestorFunctor a2 d, AncestorFunctor a3 d, AncestorFunctor a4 d) =>
-   Source m a1 x -> Sink m a2 x -> Sink m a3 x -> Sink m a4 b -> Coroutine d m r
+   (AncestorFunctor a1 d, AncestorFunctor a2 d, Monoid x, Monoid y) => Source m a1 x -> Sink m a2 y -> Coroutine d m r
+type OpenSplitter m a1 a2 a3 d x r =
+   (AncestorFunctor a1 d, AncestorFunctor a2 d, AncestorFunctor a3 d, Monoid x) =>
+   Source m a1 x -> Sink m a2 x -> Sink m a3 x -> Coroutine d m r
 
 -- | A coroutine that has no inputs nor outputs - and therefore may not suspend at all, which means it's not really a
 -- /co/routine.
@@ -72,15 +76,14 @@
 
 -- | The 'Splitter' type represents coroutines that distribute the input stream acording to some criteria. A splitter
 -- should distribute only the original input data, and feed it into the sinks in the same order it has been read from
--- the source. Furthermore, the input source should be entirely consumed and fed into the first two sinks. The third
--- sink can be used to supply extra information at arbitrary points in the input.
+-- the source. Furthermore, the input source should be entirely consumed and fed into the two sinks.
 -- 
 -- A splitter can be used in two ways: as a predicate to determine which portions of its input stream satisfy a certain
 -- property, or as a chunker to divide the input stream into chunks. In the former case, the predicate is considered
 -- true for exactly those parts of the input that are written to its /true/ sink. In the latter case, a chunk is a
--- contiguous section of the input stream that is written exclusively to one sink, either true or false. Anything
--- written to the third sink also terminates the chunk.
-newtype Splitter m x b = Splitter {split :: forall a1 a2 a3 a4 d. OpenSplitter m a1 a2 a3 a4 d x b ()}
+-- contiguous section of the input stream that is written exclusively to one sink, either true or false. A 'mempty'
+-- value written to either of the two sinks can also terminate the chunk written to the other sink.
+newtype Splitter m x = Splitter {split :: forall a1 a2 a3 d. OpenSplitter m a1 a2 a3 d x ()}
 
 -- | A 'Boundary' value is produced to mark either a 'Start' and 'End' of a region of data, or an arbitrary 'Point' in
 -- data. A 'Point' is semantically equivalent to a 'Start' immediately followed by 'End'.
@@ -90,7 +93,7 @@
 data Markup y x = Content x | Markup (Boundary y) deriving (Eq)
 
 -- | A parser is a transducer that marks up its input.
-type Parser m x b = Transducer m x (Markup b x)
+type Parser m x b = Transducer m x [Markup b x]
 
 instance Functor Boundary where
    fmap f (Start b) = Start (f b)
@@ -105,14 +108,15 @@
    showsPrec _ (Content x) s = shows x s
    showsPrec _ (Markup b) s = '[' : shows b (']' : s)
 
-instance Monad m => Category (Transducer m) where
-   id = Transducer pour
-   t1 . t2 = isolateTransducer $ \source sink-> 
-             pipe (transduce t2 source) (\source'-> transduce t1 source' sink)
-             >> return ()
+-- instance Monad m => Category (Transducer m) where
+--    id = Transducer pour
+--    t1 . t2 = isolateTransducer $ \source sink-> 
+--              pipe (transduce t2 source) (\source'-> transduce t1 source' sink)
+--              >> return ()
 
 -- | Creates a proper 'Consumer' from a function that is, but can't be proven to be, an 'OpenConsumer'.
-isolateConsumer :: forall m x r. Monad m => (forall d. Functor d => Source m d x -> Coroutine d m r) -> Consumer m x r
+isolateConsumer :: forall m x r. (Monad m, Monoid x) =>
+                   (forall d. Functor d => Source m d x -> Coroutine d m r) -> Consumer m x r
 isolateConsumer c = Consumer consume'
    where consume' :: forall a d. OpenConsumer m a d x r
          consume' source = let source' :: Source m d x
@@ -120,7 +124,8 @@
                            in c source'
 
 -- | Creates a proper 'Producer' from a function that is, but can't be proven to be, an 'OpenProducer'.
-isolateProducer :: forall m x r. Monad m => (forall d. Functor d => Sink m d x -> Coroutine d m r) -> Producer m x r
+isolateProducer :: forall m x r. (Monad m, Monoid x) =>
+                   (forall d. Functor d => Sink m d x -> Coroutine d m r) -> Producer m x r
 isolateProducer p = Producer produce'
    where produce' :: forall a d. OpenProducer m a d x r
          produce' sink = let sink' :: Sink m d x
@@ -128,7 +133,7 @@
                          in p sink'
 
 -- | Creates a proper 'Transducer' from a function that is, but can't be proven to be, an 'OpenTransducer'.
-isolateTransducer :: forall m x y. Monad m => 
+isolateTransducer :: forall m x y. (Monad m, Monoid x) =>
                      (forall d. Functor d => Source m d x -> Sink m d y -> Coroutine d m ()) -> Transducer m x y
 isolateTransducer t = Transducer transduce'
    where transduce' :: forall a1 a2 d. OpenTransducer m a1 a2 d x y ()
@@ -139,22 +144,73 @@
                                   in t source' sink'
 
 -- | Creates a proper 'Splitter' from a function that is, but can't be proven to be, an 'OpenSplitter'.
-isolateSplitter :: forall m x b. Monad m => 
-                   (forall d. Functor d => 
-                    Source m d x -> Sink m d x -> Sink m d x -> Sink m d b -> Coroutine d m ()) 
-                   -> Splitter m x b
+isolateSplitter :: forall m x b. (Monad m, Monoid x) =>
+                   (forall d. Functor d => Source m d x -> Sink m d x -> Sink m d x -> Coroutine d m ())
+                   -> Splitter m x
 isolateSplitter s = Splitter split'
-   where split' :: forall a1 a2 a3 a4 d. OpenSplitter m a1 a2 a3 a4 d x b ()
-         split' source true false edge = let source' :: Source m d x
-                                             source' = liftSource source
-                                             true' :: Sink m d x
-                                             true' = liftSink true
-                                             false' :: Sink m d x
-                                             false' = liftSink false
-                                             edge' :: Sink m d b
-                                             edge' = liftSink edge
-                                         in s source' true' false' edge'
+   where split' :: forall a1 a2 a3 d. OpenSplitter m a1 a2 a3 d x ()
+         split' source true false = let source' :: Source m d x
+                                        source' = liftSource source
+                                        true' :: Sink m d x
+                                        true' = liftSink true
+                                        false' :: Sink m d x
+                                        false' = liftSink false
+                                    in s source' true' false'
 
+
+-- | Class 'PipeableComponentPair' applies to any two components that can be combined into a third component with the
+-- following properties:
+--
+--    * The input of the result, if any, becomes the input of the first component.
+--
+--    * The output produced by the first child component is consumed by the second child component.
+--
+--    * The result output, if any, is the output of the second component.
+class PipeableComponentPair (m :: * -> *) w c1 c2 c3 | c1 c2 -> c3, c1 c3 -> c2, c2 c3 -> c2,
+                                                       c1 -> m w, c2 -> m w, c3 -> m
+   where compose :: PairBinder m -> c1 -> c2 -> c3
+
+instance forall m x. (Monad m, Monoid x) => 
+         PipeableComponentPair m x (Producer m x ()) (Consumer m x ()) (Performer m ())
+   where compose binder p c = let performPipe :: Coroutine Naught m ((), ())
+                                  performPipe = pipeG binder (produce p) (consume c)
+                              in Performer (runCoroutine performPipe >> return ())
+
+instance forall m x r. (Monad m, Monoid x) => 
+         PipeableComponentPair m x (Producer m x ()) (Consumer m x r) (Performer m r)
+   where compose binder p c = let performPipe :: Coroutine Naught m ((), r)
+                                  performPipe = pipeG binder (produce p) (consume c)
+                              in Performer (liftM snd $ runCoroutine performPipe)
+
+instance forall m x r. (Monad m, Monoid x) => 
+         PipeableComponentPair m x (Producer m x r) (Consumer m x ()) (Performer m r)
+   where compose binder p c = let performPipe :: Coroutine Naught m (r, ())
+                                  performPipe = pipeG binder (produce p) (consume c)
+                              in Performer (liftM fst $ runCoroutine performPipe)
+
+instance (Monad m, Monoid x, Monoid y) => 
+         PipeableComponentPair m y (Transducer m x y) (Consumer m y r) (Consumer m x r)
+   where compose binder t c = isolateConsumer $ \source-> 
+                              liftM snd $
+                              pipeG binder
+                                 (transduce t source)
+                                 (consume c)
+
+instance (Monad m, Monoid x, Monoid y) => 
+         PipeableComponentPair m x (Producer m x r) (Transducer m x y) (Producer m y r)
+   where compose binder p t = isolateProducer $ \sink-> 
+                              liftM fst $
+                              pipeG binder
+                                 (produce p)
+                                 (\source-> transduce t source sink)
+
+instance (Monad m, Monoid x, Monoid y, Monoid z) => 
+         PipeableComponentPair m y (Transducer m x y) (Transducer m y z) (Transducer m x z)
+   where compose binder t1 t2 = 
+            isolateTransducer $ \source sink-> 
+            pipeG binder (transduce t1 source) (\source'-> transduce t2 source' sink)
+            >> return ()
+
 -- | 'Branching' is a type class representing all types that can act as consumers, namely 'Consumer',
 -- 'Transducer', and 'Splitter'.
 class Branching c (m :: * -> *) x r | c -> m x where
@@ -180,47 +236,50 @@
                      sink' = liftSink sink
         in Transducer transduce'
 
-instance forall m x b. Monad m => Branching (Splitter m x b) m x () where
+instance forall m x b. Monad m => Branching (Splitter m x) m x () where
    combineBranches combinator binder s1 s2
-      = let split' :: forall a1 a2 a3 a4 d. OpenSplitter m a1 a2 a3 a4 d x b ()
-            split' source true false edge = combinator binder
-                                               (\source'-> split s1 source' true' false' edge')
-                                               (\source'-> split s2 source' true' false' edge')
-                                               source
+      = let split' :: forall a1 a2 a3 d. OpenSplitter m a1 a2 a3 d x ()
+            split' source true false = combinator binder
+                                          (\source'-> split s1 source' true' false')
+                                          (\source'-> split s2 source' true' false')
+                                          source
                where true' :: Sink m d x
                      true' = liftSink true
                      false' :: Sink m d x
                      false' = liftSink false
-                     edge' :: Sink m d b
-                     edge' = liftSink edge
         in Splitter split'
 
 -- | Function 'oneToOneTransducer' takes a function that maps one input value to one output value each, and lifts it
 -- into a 'Transducer'.
-oneToOneTransducer :: Monad m => (x -> y) -> Transducer m x y
+oneToOneTransducer :: (Monad m, FactorialMonoid x, Monoid y) => (x -> y) -> Transducer m x y
 oneToOneTransducer f = Transducer (mapStream f)
 
 -- | Function 'statelessTransducer' takes a function that maps one input value into a list of output values, and
 -- lifts it into a 'Transducer'.
-statelessTransducer :: Monad m => (x -> [y]) -> Transducer m x y
-statelessTransducer f = Transducer (concatMapStream f)
+statelessTransducer :: Monad m => (x -> y) -> Transducer m [x] y
+statelessTransducer f = Transducer (mapStream (mconcat . map f))
 
+-- | Function 'statelessTransducer' takes a function that maps one input value into a list of output values, and
+-- lifts it into a 'Transducer'.
+statelessChunkTransducer :: Monad m => (x -> y) -> Transducer m x y
+statelessChunkTransducer f = Transducer (mapStreamChunks f)
+
 -- | Function 'statefulTransducer' constructs a 'Transducer' from a state-transition function and the initial
 -- state. The transition function may produce arbitrary output at any transition step.
-statefulTransducer :: Monad m => (state -> x -> (state, [y])) -> state -> Transducer m x y
+statefulTransducer :: (Monad m, MonoidNull y) => (state -> x -> (state, y)) -> state -> Transducer m [x] y
 statefulTransducer f s0 = 
-   Transducer (\source sink-> foldMStream_ (\ s x -> let (s', ys) = f s x in putList ys sink >> return s') s0 source)
+   Transducer (\source sink-> foldMStream_ (\ s x -> let (s', ys) = f s x in putAll ys sink >> return s') s0 source)
 
 -- | Function 'statelessSplitter' takes a function that assigns a Boolean value to each input item and lifts it into
 -- a 'Splitter'.
-statelessSplitter :: Monad m => (x -> Bool) -> Splitter m x b
-statelessSplitter f = Splitter (\source true false _edge-> partitionStream f source true false)
+statelessSplitter :: Monad m => (x -> Bool) -> Splitter m [x]
+statelessSplitter f = Splitter (\source true false-> partitionStream f source true false)
 
 -- | Function 'statefulSplitter' takes a state-converting function that also assigns a Boolean value to each input
 -- item and lifts it into a 'Splitter'.
-statefulSplitter :: Monad m => (state -> x -> (state, Bool)) -> state -> Splitter m x ()
+statefulSplitter :: Monad m => (state -> x -> (state, Bool)) -> state -> Splitter m [x]
 statefulSplitter f s0 = 
-   Splitter (\source true false _edge-> 
+   Splitter (\source true false-> 
               foldMStream_ 
                  (\ s x -> let (s', truth) = f s x in (if truth then put true x else put false x) >> return s')
                  s0 source)
diff --git a/Control/Concurrent/SCC/XML.hs b/Control/Concurrent/SCC/XML.hs
--- a/Control/Concurrent/SCC/XML.hs
+++ b/Control/Concurrent/SCC/XML.hs
@@ -1,5 +1,5 @@
 {-
-    Copyright 2009-2011 Mario Blazevic
+    Copyright 2009-2012 Mario Blazevic
 
     This file is part of the Streaming Component Combinators (SCC) project.
 
@@ -16,7 +16,8 @@
 
 -- | Module "XML" defines primitives and combinators for parsing and manipulating XML.
 
-{-# LANGUAGE PatternGuards, FlexibleContexts, MultiParamTypeClasses, ScopedTypeVariables, Rank2Types #-}
+{-# LANGUAGE PatternGuards, FlexibleContexts, MultiParamTypeClasses, OverloadedStrings,
+             ScopedTypeVariables, Rank2Types #-}
 {-# OPTIONS_HADDOCK hide #-}
 
 module Control.Concurrent.SCC.XML (
@@ -37,13 +38,13 @@
 import Data.Maybe (mapMaybe)
 import Data.Monoid (Monoid(..))
 import Data.List (find)
+import Data.String (IsString(fromString))
 import Data.Text (Text, pack, unpack, singleton)
 import qualified Data.Text as Text
 import Numeric (readDec, readHex)
 
-import Data.Functor.Contravariant.Ticker (andThen, tickOne, tickWhile)
-import Text.ParserCombinators.Incremental (Parser, more, feed, anyToken, satisfy, concatMany, takeWhile, takeWhile1, string,
-                                           moptional, skip, lookAhead, notFollowedBy, mapIncremental, (><))
+import Text.ParserCombinators.Incremental (Parser, more, feed, anyToken, satisfy, concatMany, takeWhile, takeWhile1, 
+                                           string, moptional, skip, lookAhead, notFollowedBy, mapIncremental, (><))
 import qualified Text.ParserCombinators.Incremental.LeftBiasedLocal as LeftBiasedLocal (Parser)
 import Text.ParserCombinators.Incremental.LeftBiasedLocal (leftmost)
 import Control.Monad.Coroutine (Coroutine, sequentialBinder)
@@ -85,7 +86,7 @@
          _ -> XMLStream (l ++ r)
    XMLStream l `mappend` XMLStream r = XMLStream (l ++ r)
 
-xmlParser :: LeftBiasedLocal.Parser String XMLStream
+xmlParser :: LeftBiasedLocal.Parser Text XMLStream
 xmlParser = concatMany (xmlContent <|> xmlMarkup)
    where xmlContent = mapContent $ takeWhile1 (\x-> x /= "<" && x /= "&")
          xmlMarkup = (string "<" >> ((startTag <|> endTag <|> processingInstruction <|> declaration)
@@ -103,12 +104,12 @@
                     >< (string ">" >> return (XMLStream [Content (singleton '>'), Markup (End StartTag)])
                         <|> return (XMLStream [Markup $ Point unterminatedStartTag, Markup $ End StartTag]))
          entityReference s = string s
-                             >> (return (XMLStream [Markup (Start EntityReference), Content (pack s),
+                             >> (return (XMLStream [Markup (Start EntityReference), Content s,
                                                     Markup (Start EntityName)])
                                  >< name
                                  >< (string ";" >> return (XMLStream [Markup (End EntityName), Content (singleton ';'),
                                                                       Markup (End EntityReference)]))
-                                 <|> return (XMLStream [Markup $ Point $ errorBadEntityReference, Content (pack s)]))
+                                 <|> return (XMLStream [Markup $ Point $ errorBadEntityReference, Content s]))
          attributes = concatMany (attribute >< whiteSpace)
          attribute = return (XMLStream [Markup (Start AttributeName)])
                      >< name
@@ -117,46 +118,45 @@
                          <|> (fmap (\x-> XMLStream [Markup $ Point $ errorBadAttribute x]) anyToken
                                >< whiteSpace >< moptional (mapContent $ string "=")))
                      >< ((string "\"" <|> string "\'")
-                         >>= \quote-> return (XMLStream [Content $ pack quote, Markup (Start AttributeValue)])
+                         >>= \quote-> return (XMLStream [Content quote, Markup (Start AttributeValue)])
                                       >< mapContent (takeWhile (/= quote))
-                                      >< return (XMLStream [Markup (End AttributeValue), Content $ pack quote])
+                                      >< return (XMLStream [Markup (End AttributeValue), Content quote])
                                       >< skip (string quote)
                          <|> (anyToken >>= \q-> return (XMLStream [Markup $ Point $ errorBadQuoteCharacter q,
-                                                                    Content $ pack quote])))
-         endTag = (string "/" >> return (XMLStream [Markup (Start EndTag), Content (pack "</"),
-                                                    Markup (Start ElementName)]))
+                                                                    Content quote])))
+         endTag = (string "/" >> return (XMLStream [Markup (Start EndTag), Content "</", Markup (Start ElementName)]))
                   >< name
                   >< return (XMLStream [Markup (End ElementName)])
                   >< whiteSpace
                   >< (string ">" >> return (XMLStream [Content (singleton '>'), Markup (End EndTag)])
                       <|> return (XMLStream [Markup $ Point unterminatedEndTag, Markup (End EndTag)]))
          processingInstruction = (string "?"
-                                  >> return (XMLStream [Markup (Start ProcessingInstruction), Content (pack "<?"),
+                                  >> return (XMLStream [Markup (Start ProcessingInstruction), Content "<?",
                                                         Markup (Start ProcessingInstructionText)]))
                                  >< upto "?>"
                                  >< (string "?>"
-                                     >> return (XMLStream [Markup (End ProcessingInstructionText), Content (pack "?>"),
+                                     >> return (XMLStream [Markup (End ProcessingInstructionText), Content "?>",
                                                            Markup (End ProcessingInstruction)])
                                      <|> return (XMLStream [Markup $ Point unterminatedProcessingInstruction]))
-         declaration = string "!" 
+         declaration = string "!"
                        >> ((comment <|> cdataMarkedSection <|> doctypeDeclaration)
-                           <|> return (XMLStream [Markup $ Point $ errorBadDeclarationType, Content (pack "<")]))
-         comment = (string "--" >> return (XMLStream [Markup (Start Comment), Content (pack "<!--"),
+                           <|> return (XMLStream [Markup $ Point $ errorBadDeclarationType, Content "<"]))
+         comment = (string "--" >> return (XMLStream [Markup (Start Comment), Content "<!--",
                                                        Markup (Start CommentText)]))
                    >< upto "-->"
-                   >< (string "-->" >> return (XMLStream [Markup (End CommentText), Content (pack "-->"),
+                   >< (string "-->" >> return (XMLStream [Markup (End CommentText), Content "-->",
                                                           Markup (End Comment)])
                        <|> return (XMLStream [Markup $ Point unterminatedComment]))
          cdataMarkedSection = (string "[CDATA["
-                               >> return (XMLStream [Markup (Start StartMarkedSectionCDATA), Content (pack "<![CDATA["),
+                               >> return (XMLStream [Markup (Start StartMarkedSectionCDATA), Content "<![CDATA[",
                                                      Markup (End StartMarkedSectionCDATA)]))
                               >< upto "]]>"
                               >< (string "]]>"
-                                  >> return (XMLStream [Markup (Start EndMarkedSection), Content (pack "]]>"),
+                                  >> return (XMLStream [Markup (Start EndMarkedSection), Content "]]>",
                                                         Markup (End EndMarkedSection)])
                                   <|> return (XMLStream [Markup $ Point unterminatedMarkedSection]))
          doctypeDeclaration = (string "DOCTYPE" >> return (XMLStream [Markup (Start DoctypeDeclaration),
-                                                                       Content (pack "<!DOCTYPE")]))
+                                                                       Content "<!DOCTYPE"]))
                               >< whiteSpace
                               >< (name
                                   >< whiteSpace
@@ -172,18 +172,19 @@
                                   <|> return (XMLStream [Markup (Point errorMalformedDoctypeDeclaration)]))
                               >< return (XMLStream [Markup (End DoctypeDeclaration)])
          literal = (string "\"" <|> string "\'")
-                   >>= \quote-> return (XMLStream [Content $ pack quote])
+                   >>= \quote-> return (XMLStream [Content quote])
                                 >< mapContent (takeWhile (/= quote))
-                                >< return (XMLStream [Content $ pack quote])
+                                >< return (XMLStream [Content quote])
                                 >< skip (string quote)
          markupDeclaration= mapContent (string "<!")
                             >< (concatMany (mapContent (takeWhile1 (\x-> x /= ">" && x /= "\"" && x /= "\'")) <|> literal)
                                 >< mapContent (string ">")
                                 <|> return (XMLStream [Markup $ Point unterminatedMarkupDeclaration]))
-         name = mapContent (takeWhile1 (isNameChar . head))
-         mapContent = mapIncremental (XMLStream . (:[]) . Content . pack)
-         whiteSpace = mapContent (takeWhile (isSpace . head))
-         upto end@(lead:_) = mapContent (concatMany (takeWhile1 (/= [lead]) <|> notFollowedBy (string end) >< anyToken))
+         name = mapContent (takeWhile1 (isNameChar . Text.head))
+         mapContent = mapIncremental (XMLStream . (:[]) . Content)
+         whiteSpace = mapContent (takeWhile (isSpace . Text.head))
+         upto end@(lead:_) = mapContent (concatMany (takeWhile1 ((lead /=) . Text.head)
+                                                     <|> notFollowedBy (string $ fromString end) >< anyToken))
 
 errorBadQuoteCharacter q = ErrorToken ("Invalid quote character " ++ show q)
 errorBadAttribute x = ErrorToken ("Invalid character " ++ show x ++ " following attribute name")
@@ -203,19 +204,16 @@
 isNameChar x = isAlphaNum x || x == '_' || x == '-' || x == ':'
 
 -- | XML markup splitter wrapping 'parseXMLTokens'.
-xmlTokens :: Monad m => Splitter m Char (Boundary XMLToken)
-xmlTokens = parserToSplitter (parseXMLTokens >>> statelessTransducer unpackContent)
-   where unpackContent :: Markup XMLToken Text -> [Markup XMLToken Char]
-         unpackContent (Markup b) = [Markup b]
-         unpackContent (Content c) = map Content (unpack c)
+xmlTokens :: Monad m => Splitter m Text
+xmlTokens = parserToSplitter parseXMLTokens
 
 -- | The XML token parser. This parser converts plain text to parsed text, which is a precondition for using the
 -- remaining XML components.
-parseXMLTokens :: Monad m => Transducer m Char (Markup XMLToken Text)
+parseXMLTokens :: Monad m => Transducer m Text [Markup XMLToken Text]
 parseXMLTokens = Transducer (pourParsed (mapIncremental chunk xmlParser))
 
 dispatchOnString :: forall m a d r. (Monad m, AncestorFunctor a d) =>
-                    Source m a Char -> (String -> Coroutine d m r) -> [(String, String -> Coroutine d m r)]
+                    Source m a [Char] -> (String -> Coroutine d m r) -> [(String, String -> Coroutine d m r)]
                  -> Coroutine d m r
 dispatchOnString source failure fullCases = dispatch fullCases id
    where dispatch cases consumed
@@ -231,7 +229,7 @@
                                        | otherwise = Nothing
 
 getElementName :: forall m a d. (Monad m, AncestorFunctor a d) =>
-                  Source m a (Markup XMLToken Text) -> ([Markup XMLToken Text] -> [Markup XMLToken Text])
+                  Source m a [Markup XMLToken Text] -> ([Markup XMLToken Text] -> [Markup XMLToken Text])
                -> Coroutine d m ([Markup XMLToken Text], Maybe Text)
 getElementName source f = get source
                           >>= maybe
@@ -244,7 +242,7 @@
                                              _ -> error ("Expected an ElementName, received " ++ show x))
 
 getRestOfRegion :: forall m a d. (Monad m, AncestorFunctor a d) =>
-                   XMLToken -> Source m a (Markup XMLToken Text)
+                   XMLToken -> Source m a [Markup XMLToken Text]
                 -> ([Markup XMLToken Text] -> [Markup XMLToken Text]) -> (Text -> Text)
                 -> Coroutine d m ([Markup XMLToken Text], Maybe Text)
 getRestOfRegion token source f g = getWhile isContent source
@@ -256,8 +254,8 @@
                                                _ -> error ("Expected rest of " ++ show token ++ ", received " ++ show x)
 
 pourRestOfRegion :: forall m a1 a2 a3 d. (Monad m, AncestorFunctor a1 d, AncestorFunctor a2 d, AncestorFunctor a3 d) =>
-                    XMLToken -> Source m a1 (Markup XMLToken Text)
-                          -> Sink m a2 (Markup XMLToken Text) -> Sink m a3 (Markup XMLToken Text)
+                    XMLToken -> Source m a1 [Markup XMLToken Text]
+                           -> Sink m a2 [Markup XMLToken Text] -> Sink m a3 [Markup XMLToken Text]
                  -> Coroutine d m Bool
 pourRestOfRegion token source sink endSink = pourWhile isContent source sink
                                              >> get source
@@ -270,7 +268,7 @@
                                                                          ++ ", received " ++ show x))
 
 getRestOfStartTag :: forall m a d. (Monad m, AncestorFunctor a d) =>
-                     Source m a (Markup XMLToken Text) -> Coroutine d m ([Markup XMLToken Text], Bool)
+                     Source m a [Markup XMLToken Text] -> Coroutine d m ([Markup XMLToken Text], Bool)
 getRestOfStartTag source = do rest <- getWhile notEndTag source
                               end <- get source
                               case end of Nothing -> return (rest, False)
@@ -279,65 +277,65 @@
                                              getRestOfStartTag source
                                              >>= \(rest', _)-> return (rest ++ (e: rest'), False)
                                           _ -> error "getWhile returned early!"
-   where notEndTag (Markup (End StartTag)) = False
-         notEndTag (Markup (Point EmptyTag)) = False
+   where notEndTag [Markup (End StartTag)] = False
+         notEndTag [Markup (Point EmptyTag)] = False
          notEndTag _ = True
 
 getRestOfEndTag :: forall m a d. (Monad m, AncestorFunctor a d) =>
-                   Source m a (Markup XMLToken Text) -> Coroutine d m [Markup XMLToken Text]
-getRestOfEndTag source = getWhile (/= Markup (End EndTag)) source
+                   Source m a [Markup XMLToken Text] -> Coroutine d m [Markup XMLToken Text]
+getRestOfEndTag source = getWhile (/= [Markup (End EndTag)]) source
                          >>= \tokens-> get source
                                        >>= maybe (error "No end to the end tag!") (return . (tokens ++) . (:[]))
 
 findEndTag :: forall m a1 a2 a3 d. (Monad m, AncestorFunctor a1 d, AncestorFunctor a2 d, AncestorFunctor a3 d) =>
-              Source m a1 (Markup XMLToken Text) -> Sink m a2 (Markup XMLToken Text) -> Sink m a3 (Markup XMLToken Text)
+              Source m a1 [Markup XMLToken Text] -> Sink m a2 [Markup XMLToken Text] -> Sink m a3 [Markup XMLToken Text]
               -> Text
               -> Coroutine d m ()
 findEndTag source sink endSink name = findTag where
    findTag = pourWhile noTagStart source sink
              >> get source
              >>= maybe (return ()) consumeOne
-   noTagStart (Markup (Start StartTag)) = False
-   noTagStart (Markup (Start EndTag)) = False
+   noTagStart [Markup (Start StartTag)] = False
+   noTagStart [Markup (Start EndTag)] = False
    noTagStart _ = True
    consumeOne x@(Markup (Start EndTag)) = do (tokens, mn) <- getElementName source (x :)
                                              maybe
                                                 (return ())
                                                 (\name'-> getRestOfEndTag source
                                                           >>= \rest-> if name == name'
-                                                                      then putList (tokens ++ rest) endSink
+                                                                      then putAll (tokens ++ rest) endSink
                                                                            >> return ()
-                                                                      else putList (tokens ++ rest) sink
+                                                                      else putAll (tokens ++ rest) sink
                                                                            >> findTag)
                                                 mn
    consumeOne x@(Markup (Start StartTag)) = do (tokens, mn) <- getElementName source (x :)
                                                maybe
                                                   (return ())
                                                   (\name'-> do (rest, hasContent) <- getRestOfStartTag source
-                                                               _ <- putList (tokens ++ rest) sink
+                                                               _ <- putAll (tokens ++ rest) sink
                                                                when hasContent (findEndTag source sink sink name')
                                                                findTag)
                                                   mn
    consumeOne _ = error "pourWhile returned early!"
 
 findStartTag :: forall m a1 a2 d. (Monad m, AncestorFunctor a1 d, AncestorFunctor a2 d) =>
-                Source m a1 (Markup XMLToken Text) -> Sink m a2 (Markup XMLToken Text)
+                Source m a1 [Markup XMLToken Text] -> Sink m a2 [Markup XMLToken Text]
              -> Coroutine d m (Maybe (Markup XMLToken Text))
-findStartTag source sink = pourWhile (/= Markup (Start StartTag)) source sink >> get source
+findStartTag source sink = pourWhile (/= [Markup (Start StartTag)]) source sink >> get source
 
 -- | Splits all top-level elements with all their content to /true/, all other input to /false/.
-xmlElement :: Monad m => Splitter m (Markup XMLToken Text) ()
+xmlElement :: Monad m => Splitter m [Markup XMLToken Text]
 xmlElement = Splitter $
-             \source true false edge->
+             \source true false->
              let split0 = findStartTag source false
                           >>= maybe (return [])
-                                 (\x-> do put edge ()
+                                 (\x-> do putChunk false mempty
                                           put true x
                                           (tokens, mn) <- getElementName source id
                                           maybe
-                                             (putList tokens true)
+                                             (putAll tokens true)
                                              (\name-> do (rest, hasContent) <- getRestOfStartTag source
-                                                         _ <- putList (tokens ++ rest) true
+                                                         _ <- putAll (tokens ++ rest) true
                                                          if hasContent
                                                             then split1 name
                                                             else split0)
@@ -347,19 +345,19 @@
              in split0 >> return ()
 
 -- | Splits the content of all top-level elements to /true/, their tags and intervening input to /false/.
-xmlElementContent :: Monad m => Splitter m (Markup XMLToken Text) ()
+xmlElementContent :: Monad m => Splitter m [Markup XMLToken Text]
 xmlElementContent = Splitter $
-                    \source true false edge->
+                    \source true false->
                     let split0 = findStartTag source false
                                  >>= maybe (return [])
                                         (\x-> do put false x
                                                  (tokens, mn) <- getElementName source id
                                                  maybe
-                                                    (putList tokens false)
+                                                    (putAll tokens false)
                                                     (\name-> do (rest, hasContent) <- getRestOfStartTag source
-                                                                _ <- putList (tokens ++ rest) false
+                                                                _ <- putAll (tokens ++ rest) false
                                                                 if hasContent
-                                                                   then put edge () >> split1 name
+                                                                   then split1 name
                                                                    else split0)
                                                     mn)
                         split1 name = findEndTag source true false name
@@ -368,10 +366,9 @@
 
 -- | Similiar to @('Control.Concurrent.SCC.Combinators.having' 'element')@, except it runs the argument splitter
 -- only on each element's start tag, not on the entire element with its content.
-xmlElementHavingTagWith :: forall m b. Monad m =>
-                           Splitter m (Markup XMLToken Text) b -> Splitter m (Markup XMLToken Text) b
+xmlElementHavingTagWith :: forall m b. Monad m => Splitter m [Markup XMLToken Text] -> Splitter m [Markup XMLToken Text]
 xmlElementHavingTagWith test =
-      isolateSplitter $ \ source true false edge ->
+      isolateSplitter $ \ source true false ->
          let split0 = findStartTag source false
                       >>= maybe (return ())
                              (\x-> do (tokens, mn) <- getElementName source (x :)
@@ -379,64 +376,62 @@
                                          (return ())
                                          (\name-> do (rest, hasContent) <- getRestOfStartTag source
                                                      let tag = tokens ++ rest
-                                                     (_, found) <- pipe (putList tag) (findsTrueIn test)
-                                                     case found of Just mb -> maybe (return ()) (put edge) mb
-                                                                              >> putList tag true
-                                                                              >> split1 hasContent true name
-                                                                   Nothing -> putList tag false
-                                                                              >> split1 hasContent false name)
+                                                     (_, found) <- pipe (putAll tag) (findsTrueIn test)
+                                                     if found then putChunk false mempty
+                                                                   >> putAll tag true
+                                                                   >> split1 hasContent true name
+                                                        else putAll tag false
+                                                             >> split1 hasContent false name)
                                          mn)
              split1 hasContent sink name = when hasContent (findEndTag source sink sink name)
                                            >> split0
       in split0
 
 -- | Splits every attribute specification to /true/, everything else to /false/.
-xmlAttribute :: Monad m => Splitter m (Markup XMLToken Text) ()
+xmlAttribute :: Monad m => Splitter m [Markup XMLToken Text]
 xmlAttribute = Splitter $
-               \source true false edge->
-               let split0 = getWith
+               \source true false->
+               let split0 = getWith source
                                (\x-> case x
-                                     of Markup (Start AttributeName) ->
-                                           do put edge ()
-                                              put true x
+                                     of [Markup (Start AttributeName)] ->
+                                           do putChunk false mempty
+                                              putChunk true x
                                               pourRestOfRegion AttributeName source true true
                                                  >>= flip when split1
-                                        _ -> put false x >> split0)
-                               source
-                   split1 = getWith
+                                        _ -> putChunk false x >> split0)
+                   split1 = getWith source
                                (\x-> case x
-                                     of Markup (Start AttributeValue)
-                                           -> put true x
+                                     of [Markup (Start AttributeValue)]
+                                           -> putChunk true x
                                               >> pourRestOfRegion AttributeValue source true true
                                               >>= flip when split0
-                                        _ -> put true x >> split1)
-                               source
+                                        _ -> putChunk true x >> split1)
                in split0
 
 -- | Splits every element name, including the names of nested elements and names in end tags, to /true/, all the rest of
 -- input to /false/.
-xmlElementName :: Monad m => Splitter m (Markup XMLToken Text) ()
+xmlElementName :: Monad m => Splitter m [Markup XMLToken Text]
 xmlElementName = Splitter (splitSimpleRegions ElementName)
 
 -- | Splits every attribute name to /true/, all the rest of input to /false/.
-xmlAttributeName :: Monad m => Splitter m (Markup XMLToken Text) ()
+xmlAttributeName :: Monad m => Splitter m [Markup XMLToken Text]
 xmlAttributeName = Splitter  (splitSimpleRegions AttributeName)
 
 -- | Splits every attribute value, excluding the quote delimiters, to /true/, all the rest of input to /false/.
-xmlAttributeValue :: Monad m => Splitter m (Markup XMLToken Text) ()
+xmlAttributeValue :: Monad m => Splitter m [Markup XMLToken Text]
 xmlAttributeValue = Splitter (splitSimpleRegions AttributeValue)
 
-splitSimpleRegions :: Monad m => XMLToken -> OpenSplitter m a1 a2 a3 a4 d (Markup XMLToken Text) () ()
-splitSimpleRegions token source true false edge = split0
-   where split0 = getWith consumeOne source
-         consumeOne x@(Markup (Start token')) | token == token' = put false x
-                                                                  >> put edge ()
+splitSimpleRegions :: Monad m => XMLToken -> OpenSplitter m a1 a2 a3 d [Markup XMLToken Text] ()
+splitSimpleRegions token source true false = split0
+   where split0 = getWith source consumeOne
+         consumeOne x@[Markup (Start token')] | token == token' = putChunk false x
+                                                                  >> putChunk true mempty
                                                                   >> pourRestOfRegion token source true false
                                                                   >>= flip when split0
-         consumeOne x = put false x >> split0
+         consumeOne x = putChunk false x >> split0
 
-isContent :: Markup b x -> Bool
-isContent Content{} = True
+isContent :: [Markup b x] -> Bool
+isContent [Content{}] = True
 isContent _ = False
 
 fromContent :: Markup b x -> x
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -1,11 +1,11 @@
 Executables=${TestExecutables} shsh shsh-prof
-TestExecutables=$(addprefix test/, scc parallel benchmark-coroutine incremental-parser \
-                                   enumerator iteratee enumerator-scc)
-IterativeParserFiles=Text/ParserCombinators/Incremental.hs \
-                     Control/Applicative/Monoid.hs \
-                     $(addprefix Data/Monoid/, Cancellative.hs Factorial.hs Null.hs)
-CoroutineLibraryFiles=$(IterativeParserFiles) Data/Functor/Contravariant/Ticker.hs \
-                      $(addprefix Control/Monad/, \
+TestExecutables=$(addprefix test/, scc parallel benchmark-coroutine incremental-parser monoid-subclasses \
+                                   enumerator iteratee)
+IncrementalParserFiles=Text/ParserCombinators/Incremental.hs Control/Applicative/Monoid.hs $(MonoidSubclassFiles)
+MonoidSubclassFiles=$(addprefix Data/Monoid/, Cancellative.hs Factorial.hs Null.hs Textual.hs \
+                                              Instances/ByteString/UTF8.hs)
+CoroutineLibraryFiles=$(IncrementalParserFiles)      \
+	                   $(addprefix Control/Monad/,  \
                                   Parallel.hs Coroutine.hs Coroutine/SuspensionFunctors.hs Coroutine/Nested.hs)
 SCCCommonFiles=$(CoroutineLibraryFiles) \
                 Control/Concurrent/Configuration.hs  \
@@ -31,20 +31,18 @@
 test/benchmark-coroutine: Test/BenchmarkCoroutine.hs $(CoroutineLibraryFiles) | obj test
 	ghc --make $< -o $@ $(OptimizingOptions) -eventlog
 
-test/incremental-parser: Test/TestIncrementalParser.hs Text/ParserCombinators/Incremental.hs | obj test
+test/incremental-parser: Test/TestIncrementalParser.hs $(IncrementalParserFiles) | obj test
 	ghc --make $< -o $@ $(OptimizingOptions) -eventlog
 
+test/monoid-subclasses: Test/TestMonoidSubclasses.hs $(MonoidSubclassFiles) | obj test
+	ghc --make $< -o $@ $(OptimizingOptions) -eventlog -hide-package checkers -package quickcheck-instances
+
 test/enumerator: Test/TestEnumerator.hs $(CoroutineLibraryFiles) Control/Monad/Coroutine/Enumerator.hs | obj test
 	ghc --make $< -o $@ $(OptimizingOptions) -eventlog
 
 test/iteratee: Test/TestIteratee.hs $(CoroutineLibraryFiles) Control/Monad/Coroutine/Iteratee.hs | obj test
 	ghc --make $< -o $@ $(OptimizingOptions) -eventlog
 
-test/enumerator-scc: Test/TestEnumeratorSCC.hs $(SCCCommonFiles) \
-	                  Control/Monad/Coroutine/Enumerator.hs \
-                     Control/Concurrent/SCC/Combinators/Sequential.hs Control/Concurrent/SCC/Sequential.hs | obj test
-	ghc --make $< -o $@ $(OptimizingOptions) -eventlog
-
 test/parallel: Test/TestParallel.hs Control/Monad/Parallel.hs | obj test
 	ghc --make $< -o $@ $(OptimizingOptions) -eventlog
 
@@ -52,6 +50,9 @@
 	ghc --make $< -o $@ $(OptimizingOptions)
 
 shsh-prof: Shell.hs $(AllLibraryFiles) | prof
+	ghc --make $< -o $@ $(ProfilingOptions)
+
+test/scc-prof: Test/TestSCC.hs $(AllLibraryFiles) | prof test
 	ghc --make $< -o $@ $(ProfilingOptions)
 
 doc/index.html: $(DocumentationFiles) | doc
diff --git a/Shell.hs b/Shell.hs
--- a/Shell.hs
+++ b/Shell.hs
@@ -1,5 +1,5 @@
 {- 
-    Copyright 2008-2010 Mario Blazevic
+    Copyright 2008-2013 Mario Blazevic
 
     This file is part of the Streaming Component Combinators (SCC) project.
 
@@ -18,10 +18,11 @@
 
 module Main where
 
-import Prelude hiding (appendFile, interact, id, last, sequence)
+import Prelude hiding (appendFile, interact, id, last, null, sequence)
 import Data.List (intersperse, partition)
 import Data.Char (isAlphaNum)
 import Data.Maybe (fromJust)
+import Data.Monoid (Monoid)
 import Data.Text (Text)
 import Control.Concurrent (forkIO)
 import Control.Exception (evaluate)
@@ -34,7 +35,7 @@
 import Text.Parsec.Language (emptyDef)
 import Text.Parsec.Token
 import System.Console.GetOpt
-import System.Console.Readline
+import System.Console.Haskeline
 import System.Environment (getArgs)
 import System.IO (BufferMode (NoBuffering), hFlush, hIsWritable, hPutStrLn, hReady, hSetBuffering, stderr, stdout)
 import qualified System.Process as Process
@@ -44,14 +45,17 @@
 import System.IO (Handle, IOMode (ReadMode, WriteMode, AppendMode), openFile, hClose,
                   hGetChar, hGetContents, hPutChar, hFlush, hIsEOF, hClose, putChar, isEOF, stdout)
 
-import Control.Concurrent.Configuration (Component, atomic, showComponentTree, usingThreads, with)
 import Control.Monad.Parallel (MonadParallel)
 import Control.Monad.Coroutine
+import Data.Monoid.Null (MonoidNull(null))
+import Data.Monoid.Factorial (FactorialMonoid)
+
+import Control.Concurrent.Configuration (Component, atomic, showComponentTree, usingThreads, with)
 import Control.Concurrent.SCC.Streams
 import Control.Concurrent.SCC.Types
 import qualified Control.Concurrent.SCC.Coercions as Coercions
 import Control.Concurrent.SCC.Configurable hiding ((&&), (||))
-import Control.Concurrent.SCC.Combinators (JoinableComponentPair, compose)
+import Control.Concurrent.SCC.Combinators (JoinableComponentPair)
 import qualified Control.Concurrent.SCC.Configurable as Combinators ((&&), (||))
 
 data Expression where
@@ -68,7 +72,7 @@
    -- Void expressions, i.e. commands
    Exit             :: Expression
    -- ProducerComponent constructs
-   FromList         :: String -> Expression
+   ProduceFrom      :: String -> Expression
    FileProducer     :: String -> Expression
    StdInProducer    :: Expression
    -- ConsumerComponent constructs
@@ -136,7 +140,7 @@
                                                                    (" else " ++ showsPrec 0 f (" end foreach" ++ rest)))
    showsPrec _ Exit rest = "Exit" ++ rest
    showsPrec _ (FileProducer f) rest = "FileProducer \"" ++ f ++ "\"" ++ rest
-   showsPrec _ (FromList str) rest = "echo \"" ++ str ++ "\"" ++ rest
+   showsPrec _ (ProduceFrom str) rest = "echo \"" ++ str ++ "\"" ++ rest
    showsPrec 0 (Sequence p1 p2) rest = showsPrec 2 p1 (";\n" ++ showsPrec 0 p2 rest)
    showsPrec 1 (Sequence p1 p2) rest = showsPrec 2 p1 ("; " ++ showsPrec 1 p2 rest)
    showsPrec p e@Sequence{} rest = "(" ++ showsPrec 1 e (')' : rest)
@@ -214,10 +218,10 @@
    -- Streaming component type tags
    ComponentTag  :: TypeTag x -> TypeTag (Component x)
    CommandTag    :: TypeTag (Performer IO ())
-   ConsumerTag   :: TypeTag x -> TypeTag (Consumer IO x ())
-   ProducerTag   :: TypeTag x -> TypeTag (Producer IO x ())
-   SplitterTag   :: TypeTag x -> TypeTag b -> TypeTag (Splitter IO x b)
-   TransducerTag :: TypeTag x -> TypeTag y -> TypeTag (Transducer IO x y)
+   ConsumerTag   :: Monoid x => TypeTag x -> TypeTag (Consumer IO x ())
+   ProducerTag   :: Monoid x => TypeTag x -> TypeTag (Producer IO x ())
+   SplitterTag   :: Monoid x => TypeTag x -> TypeTag (Splitter IO x)
+   TransducerTag :: (Monoid x, Monoid y) => TypeTag x -> TypeTag y -> TypeTag (Transducer IO x y)
    GenericInputTag :: (TypeTag x -> TypeTag y) -> TypeTag y
 
 instance Show (TypeTag x) where
@@ -236,7 +240,7 @@
    show CommandTag  = "Command"
    show (ConsumerTag x) = "Consumer " ++ show x
    show (ProducerTag x) = "Producer " ++ show x
-   show (SplitterTag x b) = "Splitter " ++ shows x (" " ++ show b)
+   show (SplitterTag x) = "Splitter " ++ show x
    show (TransducerTag x y) = "Transducer " ++ shows x (" -> " ++ show y)
    show GenericInputTag{} = "Generic"
 
@@ -271,10 +275,10 @@
       (CoercibleRelation{}, IdentityRelation{}) -> Just (fmap (coerce >->) x) 
       (IdentityRelation{}, CoercibleRelation{}) -> Just (fmap (>-> coerce) x)
       _ -> Nothing
-typecoerce (ComponentTag (SplitterTag tag1 b1)) (ComponentTag (SplitterTag tag2 b2)) x = 
-   case (relateTags tag1 tag2, relateTags tag2 tag1, relateTags b1 b2)
-   of (IdentityRelation{}, IdentityRelation{}, IdentityRelation{}) -> Just x
-      (CoercibleRelation{}, CoercibleRelation{}, IdentityRelation{}) -> Just (fmap adaptSplitter x)
+typecoerce (ComponentTag (SplitterTag tag1)) (ComponentTag (SplitterTag tag2)) x = 
+   case (relateTags tag1 tag2, relateTags tag2 tag1)
+   of (IdentityRelation{}, IdentityRelation{}) -> Just x
+      (CoercibleRelation{}, CoercibleRelation{}) -> Just (fmap adaptSplitter x)
       _ -> Nothing
 typecoerce (ComponentTag a) (ComponentTag b) x = fmap (\(CComponent y)-> y) (typecoerce a b (CComponent x))
 typecoerce (ProducerTag tag1) (ProducerTag tag2) x = 
@@ -299,8 +303,12 @@
    NoRelation :: TypeTagRelation x y
 
 data TypeTagClass x where
-   ShowClass :: Show x => TypeTag x -> TypeTagClass x
    EqClass :: Eq x => TypeTag x -> TypeTagClass x
+   ListClass :: x ~ [y] => TypeTag x -> TypeTagClass x
+   MonoidClass :: Monoid x => TypeTag x -> TypeTagClass x
+   MonoidNullClass :: MonoidNull x => TypeTag x -> TypeTagClass x
+   FactorialMonoidClass :: FactorialMonoid x => TypeTag x -> TypeTagClass x
+   ShowClass :: Show x => TypeTag x -> TypeTagClass x
    NoClass :: TypeTagClass x
 
 relateTags :: forall a b. TypeTag a -> TypeTag b -> TypeTagRelation a b
@@ -310,6 +318,20 @@
 relateTags IntTag IntTag = IdentityRelation IntTag
 relateTags UnitTag UnitTag = IdentityRelation UnitTag
 relateTags XMLTokenTag XMLTokenTag = IdentityRelation XMLTokenTag
+relateTags (ListTag CharTag) (ListTag TextTag) = CoercibleRelation (ListTag CharTag) (ListTag TextTag)
+relateTags (ListTag CharTag) TextTag = CoercibleRelation (ListTag CharTag) TextTag
+relateTags (ListTag TextTag) (ListTag CharTag) = CoercibleRelation (ListTag TextTag) (ListTag CharTag)
+relateTags TextTag (ListTag CharTag) = CoercibleRelation TextTag (ListTag CharTag)
+relateTags (ListTag tag1@MarkupTag{}) (ListTag tag2@MarkupTag{}) = 
+   case relateTags tag1 tag2
+   of IdentityRelation tag' -> IdentityRelation (ListTag tag')
+      _ -> NoRelation
+relateTags (ListTag (MarkupTag tag1b tag1)) (ListTag tag2) = 
+   case relateTags (ListTag tag1) (ListTag tag2)
+   of IdentityRelation (ListTag tag') -> CoercibleRelation (ListTag (MarkupTag tag1b tag')) (ListTag tag')
+      CoercibleRelation (ListTag tag1') (ListTag tag2') -> 
+         CoercibleRelation (ListTag (MarkupTag tag1b tag1')) (ListTag tag2')
+      NoRelation -> NoRelation
 relateTags (ListTag tag1) (ListTag tag2) = 
    case relateTags tag1 tag2
    of IdentityRelation tag' -> IdentityRelation (ListTag tag')
@@ -337,19 +359,10 @@
 relateTags (TransducerTag tag1a tag1b) (TransducerTag tag2a tag2b)
    | IdentityRelation tag'a <- relateTags tag1a tag2a,
      IdentityRelation tag'b <- relateTags tag1b tag2b = IdentityRelation (TransducerTag tag'a tag'b)
-relateTags (SplitterTag tag1 tag1b) (SplitterTag tag2 tag2b) 
-   | IdentityRelation tag'b <- relateTags tag1b tag2b,
-     IdentityRelation tag' <- relateTags tag1 tag2 = IdentityRelation (SplitterTag tag' tag'b)
+relateTags (SplitterTag tag1) (SplitterTag tag2) 
+   | IdentityRelation tag' <- relateTags tag1 tag2 = IdentityRelation (SplitterTag tag')
 relateTags (ComponentTag tag1) (ComponentTag tag2)
    | IdentityRelation tag' <- relateTags tag1 tag2 = IdentityRelation (ComponentTag tag')
-
-relateTags CharTag TextTag = CoercibleRelation CharTag TextTag
-relateTags TextTag CharTag = CoercibleRelation TextTag CharTag
-relateTags (MarkupTag tag1b tag1) tag2 = 
-   case relateTags tag1 tag2
-   of IdentityRelation tag' -> CoercibleRelation (MarkupTag tag1b tag') tag'
-      CoercibleRelation tag1' tag2' -> CoercibleRelation (MarkupTag tag1b tag1') tag2'
-      NoRelation -> NoRelation
 relateTags _ _ = NoRelation
 
 constrainEq :: TypeTag x -> TypeTagClass x
@@ -368,6 +381,10 @@
    | EqClass tag1' <- constrainEq tag1, EqClass tag2' <- constrainEq tag2 = EqClass (MarkupTag tag1' tag2')
 constrainEq _ = NoClass
 
+constrainList :: TypeTag x -> TypeTagClass x
+constrainList tag@ListTag{} = ListClass tag
+constrainList _ = NoClass
+
 constrainShow :: TypeTag x -> TypeTagClass x
 constrainShow CharTag = ShowClass CharTag
 constrainShow TextTag = ShowClass TextTag
@@ -384,6 +401,23 @@
    | ShowClass tag1' <- constrainShow tag1, ShowClass tag2' <- constrainShow tag2 = ShowClass (MarkupTag tag1' tag2')
 constrainShow _ = NoClass
 
+constrainMonoid :: TypeTag x -> TypeTagClass x
+constrainMonoid TextTag = MonoidClass TextTag
+constrainMonoid UnitTag = MonoidClass UnitTag
+constrainMonoid tag@ListTag{} = MonoidClass tag
+constrainMonoid _ = NoClass
+
+constrainMonoidNull :: TypeTag x -> TypeTagClass x
+constrainMonoidNull TextTag = MonoidNullClass TextTag
+constrainMonoidNull UnitTag = MonoidNullClass UnitTag
+constrainMonoidNull tag@ListTag{} = MonoidNullClass tag
+constrainMonoidNull _ = NoClass
+
+constrainFactorialMonoid :: TypeTag x -> TypeTagClass x
+constrainFactorialMonoid TextTag = FactorialMonoidClass TextTag
+constrainFactorialMonoid tag@ListTag{} = FactorialMonoidClass tag
+constrainFactorialMonoid _ = NoClass
+
 data Flag = Command | Help | Interactive | PrettyPrint | ScriptFile String | StandardInput | Threads String
             deriving Eq
 
@@ -426,10 +460,10 @@
              then showHelp
              else case inputSourceFlag options
                   of CommandLineSource -> interpret options (concat (intersperse " " arguments)) >> return ()
-                     InteractiveSource -> interact options
+                     InteractiveSource -> runInputT defaultSettings $ interact options
                      ScriptFileSource name -> readFile name >>= interpret options >> return ()
                      StandardInputSource -> getContents >>= interpret options >> return ()
-                     UnspecifiedSource -> interact options
+                     UnspecifiedSource -> runInputT defaultSettings $ interact options
 
 prettyprint options expression = print expression
                                  >> case compile UnitTag expression
@@ -440,9 +474,8 @@
 
 showHelp = putStrLn (usageInfo usageSyntax flagList)
 
-interact options = do Just command <- readline "> "
-                      addHistory command
-                      finish <- interpret options command
+interact options = do Just command <- getInputLine "> "
+                      finish <- lift $ interpret options command
                       when (not finish) (interact options)
 
 interpret options command = case parseExpression command
@@ -461,12 +494,12 @@
 execute :: Flags -> Expression -> IO ()
 execute options (Compiled CommandTag command) = perform $ with $ adjust options command
 execute options e@(Compiled t@ProducerTag{} p) =
-   case typecoerce t (ProducerTag CharTag) p
+   case typecoerce t (ProducerTag $ TextTag) p
    of Just producer-> runCoroutine (pipe
                                        (produce $ with $ adjust options producer)
                                        (consume $ with toStdOut))
                       >> hFlush stdout
-      Nothing -> print (TypeError t (ProducerTag CharTag) e)
+      Nothing -> print (TypeError t (ProducerTag $ ListTag CharTag) e)
 execute options (Compiled tag _) = hPutStrLn stderr ("Expecting a command or a Producer Char, received a " ++ show tag)
 
 adjust Flags{threadCount= Just threads} component = usingThreads component threads
@@ -495,27 +528,30 @@
                  Compiled tag _ -> TypeError tag (TransducerTag tag2 AnyTag) right
         Compiled tag _ -> TypeError tag (ProducerTag AnyTag) left
         e@TypeError{} -> e
-compile _ (FileProducer path) = Compiled (ProducerTag CharTag) (fromFile path)
-compile _ StdInProducer = Compiled (ProducerTag CharTag) fromStdIn
-compile _ (FromList string) = Compiled (ProducerTag CharTag) (atomic "putList" 1 $ Producer $
-                                                              \sink-> putList string sink >> return ())
-compile _ (FileConsumer path) = Compiled (ConsumerTag CharTag) (toFile path)
-compile _ (FileAppend path) = Compiled (ConsumerTag CharTag) (appendFile path)
-compile inputTag Suppress = Compiled (ConsumerTag inputTag) suppress
-compile inputTag (ErrorConsumer message) = Compiled (ConsumerTag inputTag) (erroneous message)
+compile _ (FileProducer path) = Compiled (ProducerTag TextTag) (fromFile path)
+compile _ StdInProducer = Compiled (ProducerTag TextTag) fromStdIn
+compile _ (ProduceFrom string) = Compiled (ProducerTag $ ListTag CharTag) (atomic "putAll" 1 $ Producer $
+                                                                           \sink-> putAll string sink >> return ())
+compile _ (FileConsumer path) = Compiled (ConsumerTag TextTag) (toFile path)
+compile _ (FileAppend path) = Compiled (ConsumerTag TextTag) (appendFile path)
+compile inputTag Suppress | MonoidClass{} <- constrainMonoid inputTag = Compiled (ConsumerTag inputTag) suppress
+compile inputTag (ErrorConsumer message) | MonoidNullClass{} <- constrainMonoidNull inputTag =
+   Compiled (ConsumerTag inputTag) (erroneous message)
 compile inputTag (Sequence e1 e2) = compileJoin sequence inputTag e1 e2
 compile inputTag (Join e1 e2) = compileJoin join inputTag e1 e2
 compile inputTag (ForEach splitter true false) = combineSplitterAndBranches foreach inputTag splitter true false
-compile inputTag (If splitter true false) = combineSplitterAndBranches ifs inputTag splitter true false
+compile inputTag (If splitter true false) | MonoidClass{} <- constrainMonoid inputTag =
+   combineSplitterAndBranches ifs inputTag splitter true false
 compile UnitTag (NativeCommand command)
-   = Compiled (ProducerTag CharTag) $
+   = Compiled (ProducerTag TextTag) $
      atomic command ioCost $ Producer $
      \sink-> do (Nothing, Just stdout, Nothing, pid)
                    <- lift (Process.createProcess (Process.shell command){Process.std_out= Process.CreatePipe})
                 produce (with $ fromHandle stdout) sink
                 lift (hClose stdout)
-compile _ (NativeCommand command) = Compiled (TransducerTag CharTag CharTag) (atomic command ioCost $ Transducer f)
-   where f :: forall a1 a2 d. OpenTransducer IO a1 a2 d Char Char ()
+compile _ (NativeCommand command) = 
+   Compiled (TransducerTag (ListTag CharTag) (ListTag CharTag)) (atomic command ioCost $ Transducer f)
+   where f :: forall a1 a2 d. OpenTransducer IO a1 a2 d String String ()
          f source sink = do (Just stdin, Just stdout, Nothing, pid)
                                <- lift (Process.createProcess
                                            (Process.shell command){Process.std_in= Process.CreatePipe,
@@ -524,7 +560,7 @@
                                   >> hSetBuffering stdout NoBuffering)
                             interleave source stdin pid stdout sink
          interleave :: forall a1 a2 d. (AncestorFunctor a1 d, AncestorFunctor a2 d) =>
-                       Source IO a1 Char -> Handle -> Process.ProcessHandle -> Handle -> Sink IO a2 Char
+                       Source IO a1 [Char] -> Handle -> Process.ProcessHandle -> Handle -> Sink IO a2 [Char]
                     -> Coroutine d IO ()
          interleave source stdin pid stdout sink = interleave1
             where interleave1 = get source
@@ -544,77 +580,93 @@
                                         else lift (hGetChar stdout)
                                              >>= put sink
                                              >> interleaveEnd
-compile inputTag (Select e) = case compile inputTag e
-                              of Compiled (SplitterTag tag _) s -> Compiled (TransducerTag tag tag) (select s)
-                                 Compiled tag _  -> TypeError tag (SplitterTag inputTag AnyTag) e
-                                 e'@TypeError{} -> e'
+compile inputTag (Select e) | MonoidClass{} <- constrainMonoid inputTag = 
+   case compile inputTag e
+   of Compiled (SplitterTag tag) s -> Compiled (TransducerTag tag tag) (select s)
+      Compiled tag _ -> TypeError tag (SplitterTag inputTag) e
+      e'@TypeError{} -> e'
 compile inputTag (While condition body)
    = case (compile inputTag condition, compile inputTag body)
-     of (Compiled (SplitterTag tag1 _) s, Compiled tag2@TransducerTag{} t)
+     of (Compiled (SplitterTag tag1) s, Compiled tag2@TransducerTag{} t)
+           | MonoidNullClass{} <- constrainMonoidNull tag1
            -> let tag2' = TransducerTag tag1 tag1
               in tryComponentCast tag2 tag2' t body (\t'-> Compiled tag2' (while t' s))
-compile inputTag (FollowedBy left right) = combineSplitters followedBy inputTag PairTag left right
-compile inputTag (And left right) = combineSplitters (>&) inputTag PairTag left right
-compile inputTag (Or left right) = combineSplitters (>|) inputTag EitherTag left right
-compile inputTag (ZipWithAnd left right) = combineSplitters (Combinators.&&) inputTag PairTag left right
-compile inputTag (ZipWithOr left right) = combineSplitters (Combinators.||) inputTag EitherTag left right
-compile inputTag (Nested left right) = combineSplittersOfSameType nestedIn inputTag left right
+compile inputTag (FollowedBy left right) = combineFactorialSplitters followedBy inputTag left right
+compile inputTag (And left right) = combineSplitters (>&) inputTag left right
+compile inputTag (Or left right) = combineSplitters (>|) inputTag left right
+compile inputTag (ZipWithAnd left right) = combineFactorialSplitters (Combinators.&&) inputTag left right
+compile inputTag (ZipWithOr left right) = combineFactorialSplitters (Combinators.||) inputTag left right
+compile inputTag (Nested left right) = combineNullSplitters nestedIn inputTag left right
 compile inputTag (Having left right) = combineSplittersOfCoercibleTypes having inputTag left right
 compile inputTag (HavingOnly left right) = combineSplittersOfCoercibleTypes havingOnly inputTag left right
-compile inputTag (Between left right) = combineSplittersOfSameType (...) inputTag left right
-compile inputTag (Not splitter) = wrapSplitter snot inputTag splitter
-compile inputTag (First splitter) = wrapSplitter first inputTag splitter
-compile inputTag (Last splitter) = wrapSplitter last inputTag splitter
-compile inputTag (Prefix splitter) = wrapSplitter prefix inputTag splitter
-compile inputTag (Suffix splitter) = wrapSplitter suffix inputTag splitter
-compile inputTag (StartOf splitter) = wrapSplitter' startOf inputTag MaybeTag splitter
-compile inputTag (EndOf splitter) = wrapSplitter' endOf inputTag MaybeTag splitter
-compile inputTag (Prepend prefix) = wrapProducerIntoTransducer prepend inputTag prefix
-compile inputTag (Append suffix) = wrapProducerIntoTransducer append inputTag suffix
-compile inputTag (Substitute replacement) = wrapGenericProducerIntoTransducer substitute inputTag replacement
+compile inputTag (Between left right) = combineFactorialSplitters (...) inputTag left right
+compile inputTag (Not splitter) | MonoidClass{} <- constrainMonoid inputTag = wrapSplitter snot inputTag splitter
+compile inputTag (First splitter) = wrapMonoidNullSplitter first inputTag splitter
+compile inputTag (Last splitter) = wrapMonoidNullSplitter last inputTag splitter
+compile inputTag (Prefix splitter) = wrapMonoidNullSplitter prefix inputTag splitter
+compile inputTag (Suffix splitter) = wrapMonoidNullSplitter suffix inputTag splitter
+compile inputTag (StartOf splitter) = wrapMonoidNullSplitter startOf inputTag splitter
+compile inputTag (EndOf splitter) = wrapMonoidNullSplitter endOf inputTag splitter
+compile inputTag (Prepend prefix) | MonoidClass{} <- constrainMonoid inputTag =
+   wrapProducerIntoTransducer prepend inputTag prefix
+compile inputTag (Append suffix) | MonoidClass{} <- constrainMonoid inputTag =
+   wrapProducerIntoTransducer append inputTag suffix
+compile inputTag (Substitute replacement) | MonoidClass{} <- constrainMonoid inputTag =
+   wrapGenericProducerIntoTransducer substitute inputTag replacement
 compile _ ExecuteTransducer
-   = Compiled (TransducerTag CharTag CharTag) (atomic "execute" ioCost $ Transducer execute)
-     where execute :: forall a1 a2 d. OpenTransducer IO a1 a2 d Char Char ()
-           execute source sink = do let (source' :: Source IO d Char) = liftSource source
-                                    ((), command) <- pipe (pour source') getList
+   = Compiled (TransducerTag (ListTag CharTag) TextTag) (atomic "execute" ioCost $ Transducer execute)
+     where execute :: forall a1 a2 d. OpenTransducer IO a1 a2 d String Text ()
+           execute source sink = do let (source' :: Source IO d String) = liftSource source
+                                    ((), command) <- pipe (pour_ source') getAll
                                     (Nothing, Just stdout, Nothing, pid)
                                        <- lift (Process.createProcess
                                                    (Process.shell command){Process.std_out= Process.CreatePipe})
                                     produce (with $ fromHandle stdout) sink
                                     lift (hClose stdout)
 
-compile inputTag IdentityTransducer = Compiled (TransducerTag inputTag inputTag) id
-compile inputTag Count = Compiled (TransducerTag inputTag IntTag) count
-compile inputTag@(ListTag itemTag) Concatenate = Compiled (TransducerTag inputTag itemTag) concatenate
+compile inputTag IdentityTransducer | MonoidClass{} <- constrainMonoid inputTag =
+   Compiled (TransducerTag inputTag inputTag) id
+compile inputTag Count | FactorialMonoidClass{} <- constrainFactorialMonoid inputTag =
+   Compiled (TransducerTag inputTag (ListTag IntTag)) count
+compile inputTag@(ListTag itemTag) Concatenate
+   | MonoidClass{} <- constrainMonoid itemTag = Compiled (TransducerTag inputTag itemTag) concatenate
 compile inputTag Concatenate = TypeError inputTag (ListTag AnyTag) Concatenate
-compile inputTag Group = Compiled (TransducerTag inputTag (ListTag inputTag)) group
-compile t@(MarkupTag t1 t2) Unparse = Compiled (TransducerTag t t2) unparse
-compile inputTag Unparse
-   = TypeError (TransducerTag (MarkupTag AnyTag AnyTag) AnyTag) (TransducerTag inputTag AnyTag) Unparse
-compile _ Uppercase = Compiled (TransducerTag CharTag CharTag) uppercase
-compile inputTag ShowTransducer  
-   | ShowClass{} <- constrainShow inputTag = Compiled (TransducerTag inputTag (ListTag CharTag)) toString
-compile inputTag ShowTransducer
-   = TypeError (TransducerTag IntTag (ListTag CharTag)) (TransducerTag inputTag AnyTag) ShowTransducer
-compile inputTag EverythingSplitter = Compiled (SplitterTag inputTag UnitTag) everything
-compile inputTag NothingSplitter = Compiled (SplitterTag inputTag UnitTag) nothing
-compile _ WhitespaceSplitter = Compiled (SplitterTag CharTag UnitTag) whitespace
-compile _ LineSplitter = Compiled (SplitterTag CharTag UnitTag) line
-compile _ LetterSplitter = Compiled (SplitterTag CharTag UnitTag) letters
-compile _ DigitSplitter = Compiled (SplitterTag CharTag UnitTag) digits
-compile inputTag@(MarkupTag tag _) MarkedSplitter 
-   | EqClass{} <- constrainEq tag = Compiled (SplitterTag inputTag UnitTag) marked
-compile _ MarkedSplitter = Compiled (SplitterTag (MarkupTag AnyTag AnyTag) UnitTag) marked
-compile inputTag OneSplitter = Compiled (SplitterTag inputTag UnitTag) one
-compile _ (SubstringSplitter part) = Compiled (SplitterTag CharTag UnitTag) (substring part)
-compile _ XMLTokenParser = Compiled (TransducerTag CharTag (MarkupTag XMLTokenTag TextTag)) xmlParseTokens
-compile _ XMLElement = Compiled (SplitterTag (MarkupTag XMLTokenTag TextTag) UnitTag) xmlElement
-compile _ XMLAttribute = Compiled (SplitterTag (MarkupTag XMLTokenTag TextTag) UnitTag) xmlAttribute
-compile _ XMLAttributeName = Compiled (SplitterTag (MarkupTag XMLTokenTag TextTag) UnitTag) xmlAttributeName
-compile _ XMLAttributeValue = Compiled (SplitterTag (MarkupTag XMLTokenTag TextTag) UnitTag) xmlAttributeValue
-compile _ XMLElementContent = Compiled (SplitterTag (MarkupTag XMLTokenTag TextTag) UnitTag) xmlElementContent
-compile _ XMLElementName = Compiled (SplitterTag (MarkupTag XMLTokenTag TextTag) UnitTag) xmlElementName
-compile _ (XMLElementHavingTag s) = wrapConcreteSplitter xmlElementHavingTagWith (MarkupTag XMLTokenTag TextTag) s
+compile inputTag Group | MonoidClass{} <- constrainMonoid inputTag =
+   Compiled (TransducerTag inputTag (ListTag inputTag)) group
+compile t@(ListTag (MarkupTag t1 t2)) Unparse 
+   | MonoidClass{} <- constrainMonoid t2 = Compiled (TransducerTag t t2) unparse
+compile inputTag Unparse | MonoidClass{} <- constrainMonoid inputTag = 
+   TypeError (TransducerTag (ListTag $ MarkupTag AnyTag AnyTag) AnyTag) (TransducerTag inputTag AnyTag) Unparse
+compile _ Uppercase = Compiled (TransducerTag (ListTag CharTag) (ListTag CharTag)) uppercase
+compile inputTag@(ListTag itemTag) ShowTransducer | ShowClass{} <- constrainShow itemTag = 
+   Compiled (TransducerTag inputTag (ListTag $ ListTag CharTag)) toString
+compile inputTag ShowTransducer | MonoidClass{} <- constrainMonoid inputTag =
+   TypeError (TransducerTag (ListTag IntTag) (ListTag $ ListTag CharTag)) (TransducerTag inputTag AnyTag) ShowTransducer
+compile inputTag EverythingSplitter | MonoidClass{} <- constrainMonoid inputTag =
+   Compiled (SplitterTag inputTag) everything
+compile inputTag NothingSplitter | MonoidClass{} <- constrainMonoid inputTag =
+   Compiled (SplitterTag inputTag) nothing
+compile _ WhitespaceSplitter = Compiled (SplitterTag (ListTag CharTag)) whitespace
+compile _ LineSplitter = Compiled (SplitterTag (ListTag CharTag)) line
+compile _ LetterSplitter = Compiled (SplitterTag (ListTag CharTag)) letters
+compile _ DigitSplitter = Compiled (SplitterTag (ListTag CharTag)) digits
+compile inputTag@(ListTag (MarkupTag tag _)) MarkedSplitter
+   | EqClass{} <- constrainEq tag = Compiled (SplitterTag inputTag) marked
+compile _ MarkedSplitter = Compiled (SplitterTag (ListTag $ MarkupTag AnyTag AnyTag)) marked
+compile inputTag OneSplitter | FactorialMonoidClass{} <- constrainFactorialMonoid inputTag =
+   Compiled (SplitterTag inputTag) one
+-- compile inputTag (SubstringSplitter part) | FactorialMonoidClass{} <- constrainFactorialMonoid inputTag =
+--    Compiled (SplitterTag inputTag) (substring part)
+compile _ (SubstringSplitter part) = Compiled (SplitterTag (ListTag CharTag)) (substring part)
+compile _ XMLTokenParser = Compiled (TransducerTag TextTag (ListTag $ MarkupTag XMLTokenTag TextTag)) xmlParseTokens
+compile _ XMLElement = Compiled (SplitterTag (ListTag $ MarkupTag XMLTokenTag TextTag)) xmlElement
+compile _ XMLAttribute = Compiled (SplitterTag (ListTag $ MarkupTag XMLTokenTag TextTag)) xmlAttribute
+compile _ XMLAttributeName = Compiled (SplitterTag (ListTag $ MarkupTag XMLTokenTag TextTag)) xmlAttributeName
+compile _ XMLAttributeValue = Compiled (SplitterTag (ListTag $ MarkupTag XMLTokenTag TextTag)) xmlAttributeValue
+compile _ XMLElementContent = Compiled (SplitterTag (ListTag $ MarkupTag XMLTokenTag TextTag)) xmlElementContent
+compile _ XMLElementName = Compiled (SplitterTag (ListTag $ MarkupTag XMLTokenTag TextTag)) xmlElementName
+compile _ (XMLElementHavingTag s) = 
+   wrapConcreteSplitter xmlElementHavingTagWith (ListTag $ MarkupTag XMLTokenTag TextTag) s
 
 compile inputTag expression = error ("Cannot compile " ++ show expression ++ " with input " ++ show inputTag)
 
@@ -658,47 +710,48 @@
         (Compiled tag@SplitterTag{} _, _) -> TypeError tag (ProducerTag AnyTag) e1
         (_, Compiled tag@SplitterTag{} _) -> TypeError tag (ProducerTag AnyTag) e2
 
-wrapSplitter :: forall x. 
-                (forall x b. SplitterComponent IO x b -> SplitterComponent IO x b) ->
+wrapSplitter :: forall x. Monoid x =>
+                (forall x. Monoid x => SplitterComponent IO x -> SplitterComponent IO x) ->
                 TypeTag x -> Expression -> Expression
 wrapSplitter combinator inputTag expression
    = case compile inputTag expression
-     of Compiled tag@(SplitterTag tx tb) splitter -> Compiled (SplitterTag tx tb) (combinator splitter)
-        Compiled tag _ -> TypeError tag (SplitterTag inputTag AnyTag) expression
+     of Compiled tag@(SplitterTag tx) splitter -> Compiled (SplitterTag tx) (combinator splitter)
+        Compiled tag _ -> TypeError tag (SplitterTag inputTag) expression
         e@TypeError{} -> e
 
-wrapConcreteSplitter :: forall x.
-                        (forall b. SplitterComponent IO x b -> SplitterComponent IO x b) ->
+wrapMonoidNullSplitter :: forall x.
+                          (forall x. MonoidNull x => SplitterComponent IO x -> SplitterComponent IO x) ->
+                          TypeTag x -> Expression -> Expression
+wrapMonoidNullSplitter combinator inputTag expression
+   = case compile inputTag expression
+     of Compiled tag@(SplitterTag tx) splitter | MonoidNullClass{} <- constrainMonoidNull tx ->
+           Compiled (SplitterTag tx) (combinator splitter)
+        Compiled tag _ | MonoidClass{} <- constrainMonoid inputTag -> TypeError tag (SplitterTag inputTag) expression
+        e@TypeError{} -> e
+
+wrapConcreteSplitter :: forall x. Monoid x =>
+                        (SplitterComponent IO x -> SplitterComponent IO x) ->
                         TypeTag x -> Expression -> Expression
 wrapConcreteSplitter combinator inputTag expression
    = case compile inputTag expression
-     of Compiled tag@(SplitterTag tx tb) splitter ->
-           tryComponentCast tag (SplitterTag inputTag tb) splitter expression $
-                   \s'-> Compiled (SplitterTag inputTag tb) (combinator s')
-        Compiled tag _ -> TypeError tag (SplitterTag inputTag AnyTag) expression
+     of Compiled tag@(SplitterTag tx) splitter ->
+           tryComponentCast tag (SplitterTag inputTag) splitter expression $
+                   \s'-> Compiled (SplitterTag inputTag) (combinator s')
+        Compiled tag _ -> TypeError tag (SplitterTag inputTag) expression
         e@TypeError{} -> e
 
-wrapConcreteSplitter' :: forall x y.
-                         (forall b. SplitterComponent IO x b -> SplitterComponent IO y ()) ->
+wrapConcreteSplitter' :: forall x y. (Monoid x, Monoid y) =>
+                         (SplitterComponent IO x -> SplitterComponent IO y) ->
                          TypeTag x -> TypeTag y -> Expression -> Expression
 wrapConcreteSplitter' combinator inputTag outputTag expression
    = case compile inputTag expression
-     of Compiled tag@(SplitterTag tx tb) splitter ->
-           tryComponentCast tag (SplitterTag inputTag tb) splitter expression $
-                            \s'-> Compiled (SplitterTag outputTag UnitTag) (combinator s')
-        Compiled tag _ -> TypeError tag (SplitterTag inputTag AnyTag) expression
-        e@TypeError{} -> e
-
-wrapSplitter' :: forall x c.
-                (forall x b. SplitterComponent IO x b -> SplitterComponent IO x (c b)) ->
-                TypeTag x -> (forall b. TypeTag b -> TypeTag (c b)) -> Expression -> Expression
-wrapSplitter' combinator inputTag constructor expression
-   = case compile inputTag expression
-     of Compiled tag@(SplitterTag tx tb) splitter -> Compiled (SplitterTag tx (constructor tb)) (combinator splitter)
-        Compiled tag _ -> TypeError tag (SplitterTag inputTag AnyTag) expression
+     of Compiled tag@(SplitterTag tx) splitter ->
+           tryComponentCast tag (SplitterTag inputTag) splitter expression $
+                            \s'-> Compiled (SplitterTag outputTag) (combinator s')
+        Compiled tag _ -> TypeError tag (SplitterTag inputTag) expression
         e@TypeError{} -> e
 
-wrapProducerIntoTransducer :: forall x.
+wrapProducerIntoTransducer :: forall x. Monoid x =>
                               (ProducerComponent IO x () -> TransducerComponent IO x x) -> TypeTag x -> Expression -> Expression
 wrapProducerIntoTransducer combinator inputTag expression
    = case compile inputTag expression
@@ -708,8 +761,8 @@
         Compiled tag _ -> TypeError tag (ProducerTag inputTag) expression
         e@TypeError{} -> e
 
-wrapGenericProducerIntoTransducer :: forall x.
-                                     (forall y r. ProducerComponent IO y r -> TransducerComponent IO x y)
+wrapGenericProducerIntoTransducer :: forall x. Monoid x =>
+                                     (forall y r. Monoid y => ProducerComponent IO y r -> TransducerComponent IO x y)
                                         -> TypeTag x -> Expression -> Expression
 wrapGenericProducerIntoTransducer combinator inputTag expression
    = case compile inputTag expression
@@ -717,135 +770,131 @@
         Compiled tag _ -> TypeError tag (ProducerTag inputTag) expression
         e@TypeError{} -> e
 
-combineSplitters :: forall x c.
-                    (forall x b1 b2. SplitterComponent IO x b1 -> SplitterComponent IO x b2 -> SplitterComponent IO x (c b1 b2))
-                       -> TypeTag x -> (forall b1 b2. TypeTag b1 -> TypeTag b2 -> TypeTag (c b1 b2))
-                       -> Expression -> Expression -> Expression
-combineSplitters combinator inputTag constructor left right
+combineSplitters :: forall x.
+                    (forall x. Monoid x => SplitterComponent IO x -> SplitterComponent IO x -> SplitterComponent IO x)
+                    -> TypeTag x -> Expression -> Expression -> Expression
+combineSplitters combinator inputTag left right
    = case (compile inputTag left, compile inputTag right)
-     of (Compiled tag1@(SplitterTag x1 b1) s1, Compiled tag2@(SplitterTag x2 b2) s2)
-           -> tryComponentCast tag2 (SplitterTag x1 b2) s2 right $
-              \s2'-> Compiled (SplitterTag x1 (constructor b1 b2)) (combinator s1 s2')
+     of (Compiled tag1@(SplitterTag x1) s1, Compiled tag2@(SplitterTag x2) s2)
+           -> tryComponentCast tag2 (SplitterTag x1) s2 right $
+              \s2'-> Compiled (SplitterTag x1) (combinator s1 s2')
         (e@TypeError{}, _) -> e
         (_, e@TypeError{}) -> e
         (Compiled tag1 _, Compiled tag2@SplitterTag{} _) -> TypeError tag1 tag2 left
         (Compiled tag1@SplitterTag{} _, Compiled tag2 _) -> TypeError tag2 tag1 right
 
-combineSplittersOfSameType :: forall x.
-                              (forall x b. SplitterComponent IO x b -> SplitterComponent IO x b -> SplitterComponent IO x b)
-                           -> TypeTag x -> Expression -> Expression -> Expression
-combineSplittersOfSameType combinator inputTag left right
+combineFactorialSplitters :: forall x c.
+                        (forall x. FactorialMonoid x => 
+                         SplitterComponent IO x -> SplitterComponent IO x -> SplitterComponent IO x)
+                        -> TypeTag x
+                        -> Expression -> Expression -> Expression
+combineFactorialSplitters combinator inputTag left right
    = case (compile inputTag left, compile inputTag right)
-     of (Compiled tag1@SplitterTag{} s1, Compiled tag2@SplitterTag{} s2)
-           -> tryComponentCast tag2 tag1 s2 right (\s2'-> Compiled tag1 (combinator s1 s2'))
+     of (Compiled tag1@(SplitterTag x1) s1, Compiled tag2@(SplitterTag x2) s2)
+         | FactorialMonoidClass{} <- constrainFactorialMonoid x1
+           -> tryComponentCast tag2 (SplitterTag x1) s2 right $
+              \s2'-> Compiled (SplitterTag x1) (combinator s1 s2')
         (e@TypeError{}, _) -> e
         (_, e@TypeError{}) -> e
         (Compiled tag1 _, Compiled tag2@SplitterTag{} _) -> TypeError tag1 tag2 left
         (Compiled tag1@SplitterTag{} _, Compiled tag2 _) -> TypeError tag2 tag1 right
 
-combineSplittersOfCoercibleTypes :: 
-   forall x. (forall x y b1 b2. Coercions.Coercible x y =>
-              SplitterComponent IO x b1 -> SplitterComponent IO y b2 -> SplitterComponent IO x b1)
-   -> TypeTag x -> Expression -> Expression -> Expression
-combineSplittersOfCoercibleTypes combinator inputTag left right
+combineNullSplitters :: forall x c.
+                        (forall x. MonoidNull x => 
+                         SplitterComponent IO x -> SplitterComponent IO x -> SplitterComponent IO x)
+                        -> TypeTag x
+                        -> Expression -> Expression -> Expression
+combineNullSplitters combinator inputTag left right
    = case (compile inputTag left, compile inputTag right)
-     of (Compiled ts1@(SplitterTag tag1 tag1b) s1, Compiled ts2@(SplitterTag tag2 _) s2)
-           -> case relateTags tag1 tag2
-              of IdentityRelation tag'-> Compiled (SplitterTag tag' tag1b) (combinator s1 s2)
-                 CoercibleRelation tag1' tag2'-> Compiled (SplitterTag tag1' tag1b) (combinator s1 s2)
-                 NoRelation -> TypeError ts2 ts1 right
-        (e@TypeError{}, _) -> e
-        (_, e@TypeError{}) -> e
-        (Compiled tag1 _, Compiled tag2@SplitterTag{} _) -> TypeError tag1 tag2 left
-        (Compiled tag1@SplitterTag{} _, Compiled tag2 _) -> TypeError tag2 tag1 right
-
-combineSplittersOfDifferentTypes :: forall x1 x2.
-                                    (forall b1 b2. SplitterComponent IO x1 b1 -> SplitterComponent IO x2 b2 -> SplitterComponent IO x1 b1)
-                                 -> TypeTag x1 -> TypeTag x2 -> Expression -> Expression -> Expression
-combineSplittersOfDifferentTypes combinator tag1 tag2 left right
-   = case (compile tag1 left, compile tag2 right)
-     of (Compiled tag1'@(SplitterTag _ b1) s1, Compiled tag2'@(SplitterTag _ b2) s2)
-           -> tryComponentCast tag1' (SplitterTag tag1 b1) s1 left $
-              \s1'-> tryComponentCast tag2' (SplitterTag tag2 b2) s2 right $
-                     \s2'-> Compiled (SplitterTag tag1 b1) (combinator s1' s2')
+     of (Compiled tag1@(SplitterTag x1) s1, Compiled tag2@(SplitterTag x2) s2)
+         | MonoidNullClass{} <- constrainMonoidNull x1
+           -> tryComponentCast tag2 (SplitterTag x1) s2 right $
+              \s2'-> Compiled (SplitterTag x1) (combinator s1 s2')
         (e@TypeError{}, _) -> e
         (_, e@TypeError{}) -> e
         (Compiled tag1 _, Compiled tag2@SplitterTag{} _) -> TypeError tag1 tag2 left
         (Compiled tag1@SplitterTag{} _, Compiled tag2 _) -> TypeError tag2 tag1 right
 
-combineXMLTextSplitters :: forall x1.
-                           (forall b1 b2.
-                            SplitterComponent IO x1 b1 -> SplitterComponent IO Text b2 -> SplitterComponent IO x1 b1)
-                        -> TypeTag x1 -> Expression -> Expression -> Expression
-combineXMLTextSplitters combinator tag left right
-   = case (compile tag left, compile CharTag right)
-     of (Compiled tag1'@(SplitterTag _ b1) s1, Compiled tag2'@(SplitterTag tag' b2) s2)
-           -> tryComponentCast tag1' (SplitterTag tag b1) s1 left $
-              \s1'-> tryComponentCast tag2' (SplitterTag TextTag b2) s2 right $
-                     \s2'-> Compiled (SplitterTag tag b1) (combinator s1' s2')
+combineSplittersOfCoercibleTypes :: 
+   forall x. (forall x y. (MonoidNull x, MonoidNull y, Coercions.Coercible x y) =>
+              SplitterComponent IO x -> SplitterComponent IO y -> SplitterComponent IO x)
+   -> TypeTag x -> Expression -> Expression -> Expression
+combineSplittersOfCoercibleTypes combinator inputTag left right
+   = case (compile inputTag left, compile inputTag right)
+     of (Compiled ts1@(SplitterTag tag1) s1, Compiled ts2@(SplitterTag tag2) s2)
+           | MonoidNullClass{} <- constrainMonoidNull tag1, MonoidNullClass{} <- constrainMonoidNull tag2
+           -> case relateTags tag1 tag2
+              of IdentityRelation tag'-> Compiled (SplitterTag tag') (combinator s1 s2)
+                 CoercibleRelation tag1' tag2'-> Compiled (SplitterTag tag1') (combinator s1 s2)
+                 NoRelation -> TypeError ts2 ts1 right
         (e@TypeError{}, _) -> e
         (_, e@TypeError{}) -> e
         (Compiled tag1 _, Compiled tag2@SplitterTag{} _) -> TypeError tag1 tag2 left
         (Compiled tag1@SplitterTag{} _, Compiled tag2 _) -> TypeError tag2 tag1 right
 
-combineTransducersOfSameType :: forall x.
-                                (forall x y. TransducerComponent IO x y -> TransducerComponent IO x y -> TransducerComponent IO x y)
-                             -> TypeTag x -> Expression -> Expression -> Expression
-combineTransducersOfSameType combinator inputTag left right
-   = case (compile inputTag left, compile inputTag right)
-     of (Compiled tag1@TransducerTag{} t1, Compiled tag2@TransducerTag{} t2)
-           -> tryComponentCast tag2 tag1 t2 right (\t2'-> Compiled tag1 (combinator t1 t2'))
-
 combineSplitterAndBranches :: forall x.
-                              (forall x b cc. Branching cc IO x () => SplitterComponent IO x b -> Component cc -> Component cc -> Component cc)
-                           -> TypeTag x -> Expression -> Expression -> Expression -> Expression
+                              (forall x b cc. (MonoidNull x, Branching cc IO x ()) => 
+                               SplitterComponent IO x -> Component cc -> Component cc -> Component cc)
+                              -> TypeTag x -> Expression -> Expression -> Expression -> Expression
 combineSplitterAndBranches combinator inputTag splitter true false
    = case (compile inputTag splitter, compile inputTag true, compile inputTag false)
-     of (Compiled (SplitterTag tag1 _) s, Compiled tag2@ConsumerTag{} t, Compiled tag3@ConsumerTag{} f)
+     of (Compiled (SplitterTag tag1) s, Compiled tag2@ConsumerTag{} t, Compiled tag3@ConsumerTag{} f)
+           | MonoidNullClass{} <- constrainMonoidNull tag1
            -> tryComponentCast tag2 (ConsumerTag tag1) t true $
               \t'-> tryComponentCast tag3 (ConsumerTag tag1) f false $
                        \f'-> Compiled (ConsumerTag tag1) (combinator s t' f')
-        (Compiled tag1@SplitterTag{} s, Compiled tag2@SplitterTag{} t, Compiled tag3@SplitterTag{} f)
+        (Compiled tag1@(SplitterTag tag1i) s, Compiled tag2@SplitterTag{} t, Compiled tag3@SplitterTag{} f)
+           | MonoidNullClass{} <- constrainMonoidNull tag1i
            -> tryComponentCast tag2 tag1 t true $
               \t'-> tryComponentCast tag3 tag1 f false $
                        \f'-> Compiled tag1 (combinator s t' f')
-        (Compiled (SplitterTag tag1 _) s, Compiled tag2@(TransducerTag tag2a tag2b) t, Compiled tag3@TransducerTag{} f)
+        (Compiled (SplitterTag tag1) s, Compiled tag2@(TransducerTag tag2a tag2b) t, Compiled tag3@TransducerTag{} f)
+           | MonoidNullClass{} <- constrainMonoidNull tag1
            -> let tag2' = TransducerTag tag1 tag2b
               in tryComponentCast tag2 tag2' t true $
                     \t'-> tryComponentCast tag3 tag2' f false $
                              \f'-> Compiled tag2' (combinator s t' f')
-        (Compiled (SplitterTag tag1 _) s, Compiled tag2@(TransducerTag tag2a tag2b) t, Compiled tag3@ConsumerTag{} f)
+        (Compiled (SplitterTag tag1) s, Compiled tag2@(TransducerTag tag2a tag2b) t, Compiled tag3@ConsumerTag{} f)
+           | MonoidNullClass{} <- constrainMonoidNull tag1
            -> let tag2' = TransducerTag tag1 tag2b
               in tryComponentCast tag2 tag2' t true $
                     \t'-> tryComponentCast tag3 (ConsumerTag tag1) f false $
                              \f'-> Compiled tag2' (combinator s t' (consumeBy f'))
-        (Compiled (SplitterTag tag1 _) s, Compiled tag2@ConsumerTag{} t, Compiled tag3@(TransducerTag tag3a tag3b) f)
+        (Compiled (SplitterTag tag1) s, Compiled tag2@ConsumerTag{} t, Compiled tag3@(TransducerTag tag3a tag3b) f)
+           | MonoidNullClass{} <- constrainMonoidNull tag1
            -> let tag3' = TransducerTag tag1 tag3b
               in tryComponentCast tag2 (ConsumerTag tag1) t true $
                     \t'-> tryComponentCast tag3 tag3' f false $
                              \f'-> Compiled tag3' (combinator s (consumeBy t') f')
-        (Compiled (SplitterTag tag1 _) s, Compiled tag2@(TransducerTag tag2a tag2b) t, Compiled tag3@ProducerTag{} f)
+        (Compiled (SplitterTag tag1) s, Compiled tag2@(TransducerTag tag2a tag2b) t, Compiled tag3@ProducerTag{} f)
+           | MonoidNullClass{} <- constrainMonoidNull tag1
            -> let tag2' = TransducerTag tag1 tag2b
               in tryComponentCast tag2 tag2' t true $
                     \t'-> tryComponentCast tag3 (ProducerTag tag2b) f false $
                              \f'-> Compiled tag2' (combinator s t' (substitute f'))
-        (Compiled (SplitterTag tag1 _) s, Compiled tag2@ProducerTag{} t, Compiled tag3@(TransducerTag tag3a tag3b) f)
+        (Compiled (SplitterTag tag1) s, Compiled tag2@ProducerTag{} t, Compiled tag3@(TransducerTag tag3a tag3b) f)
+           | MonoidNullClass{} <- constrainMonoidNull tag1
            -> let tag3' = TransducerTag tag1 tag3b
               in tryComponentCast tag2 (ProducerTag tag3b) t true $
                     \t'-> tryComponentCast tag3 tag3' f false $
                              \f'-> Compiled tag3' (combinator s (substitute t') f')
-        (Compiled (SplitterTag tag1 _) s, Compiled tag2@(ConsumerTag tag2a) t, Compiled tag3@(ProducerTag tag3a) f)
+        (Compiled (SplitterTag tag1) s, Compiled tag2@(ConsumerTag tag2a) t, Compiled tag3@(ProducerTag tag3a) f)
+           | MonoidNullClass{} <- constrainMonoidNull tag1
            -> tryComponentCast tag2 (ConsumerTag tag1) t true $
                  \t'-> Compiled (TransducerTag tag1 tag3a) (combinator s (consumeBy t') (substitute f))
-        (Compiled (SplitterTag tag1 _) s, Compiled tag2@(ProducerTag tag2a) t, Compiled tag3@(ConsumerTag tag3a) f)
+        (Compiled (SplitterTag tag1) s, Compiled tag2@(ProducerTag tag2a) t, Compiled tag3@(ConsumerTag tag3a) f)
+           | MonoidNullClass{} <- constrainMonoidNull tag1
            -> tryComponentCast tag3 (ConsumerTag tag1) f true $
                  \f'-> Compiled (TransducerTag tag1 tag2a) (combinator s (substitute t) (consumeBy f'))
         (e@TypeError{}, _, _) -> e
         (_, e@TypeError{}, _) -> e
         (_, _, e@TypeError{}) -> e
-        (Compiled SplitterTag{} _, Compiled tag _, _) -> TypeError tag (TransducerTag inputTag AnyTag) true
-        (Compiled SplitterTag{} _, _, Compiled tag _) -> TypeError tag (TransducerTag inputTag AnyTag) false
-        (Compiled tag _, _, _) -> TypeError tag (SplitterTag inputTag AnyTag) splitter
+        (Compiled SplitterTag{} _, Compiled tag _, _)
+           | MonoidClass{} <- constrainMonoid inputTag -> TypeError tag (TransducerTag inputTag AnyTag) true
+        (Compiled SplitterTag{} _, _, Compiled tag _)
+           | MonoidClass{} <- constrainMonoid inputTag -> TypeError tag (TransducerTag inputTag AnyTag) false
+        (Compiled tag _, _, _) 
+           | MonoidClass{} <- constrainMonoid inputTag -> TypeError tag (SplitterTag inputTag) splitter
 
 parseExpression :: String -> Either Int (Expression, [Char], Int)
 parseExpression s = case Parsec.parse partialExpressionParser "" s of
@@ -945,7 +994,7 @@
    <|> try (nativeSourceParser "ls")
    <|> try (do symbol lexer "echo"
                string <- nativeCommand True
-               return (FromList string))
+               return (ProduceFrom string))
    <|> try (symbol lexer "stdin" >> return StdInProducer)
    <|> try (do symbol lexer ">>"
                file <- parameterParser True
diff --git a/Test/TestSCC.hs b/Test/TestSCC.hs
--- a/Test/TestSCC.hs
+++ b/Test/TestSCC.hs
@@ -1,5 +1,5 @@
 {- 
-    Copyright 2008-2010 Mario Blazevic
+    Copyright 2008-2012 Mario Blazevic
 
     This file is part of the Streaming Component Combinators (SCC) project.
 
@@ -18,14 +18,8 @@
 
 module Main where
 
-import Control.Concurrent.Configuration
-import Control.Monad.Coroutine
-import Control.Concurrent.SCC.Streams
-import Control.Concurrent.SCC.Types
-import qualified Control.Concurrent.SCC.Combinators as Combinator
-import Control.Concurrent.SCC.Configurable hiding ((&&), (||))
-import qualified Control.Concurrent.SCC.XML as XML
-import qualified Control.Concurrent.SCC.Configurable as C
+import Prelude hiding (even, id, last)
+import qualified Prelude
 
 import Control.Monad (liftM, when)
 import Data.Char (ord, isLetter, isSpace, toUpper)
@@ -34,19 +28,29 @@
 import Data.List (find, findIndices, groupBy, intersect, union,
                   intercalate, isInfixOf, isPrefixOf, isSuffixOf, nub, sort, tails)
 import Data.Maybe (fromJust, isJust, mapMaybe)
+import Data.Monoid (Monoid)
+import Data.Monoid.Null (MonoidNull)
 import qualified Data.List as List
 import qualified Data.Foldable as Foldable
 import qualified Data.Sequence as Seq
 import Data.Sequence (Seq, (|>), (><), ViewL (EmptyL, (:<)))
-import Debug.Trace (trace)
-import Prelude hiding (even, id, last)
-import qualified Prelude
+import Data.String (IsString(fromString))
+
 import Test.QuickCheck (Arbitrary, Gen, Property, CoArbitrary,
                         Positive(Positive), NonNegative(NonNegative), NonEmptyList(NonEmpty),
                         arbitrary, coarbitrary, label, classify, choose, mapSize, oneof, resize, sized,
                         quickCheck, variant, (==>))
 
+import Control.Concurrent.Configuration
+import Control.Monad.Coroutine
+import Control.Concurrent.SCC.Streams
+import Control.Concurrent.SCC.Types
+import qualified Control.Concurrent.SCC.Combinators as Combinator
+import Control.Concurrent.SCC.Configurable hiding ((&&), (||))
+import qualified Control.Concurrent.SCC.XML as XML
+import qualified Control.Concurrent.SCC.Configurable as C
 
+
 sublists [] _ = []
 sublists _ [] = []
 sublists sublist input = map
@@ -62,7 +66,7 @@
 
 main = mapM_ quickCheck tests
 
-tests = [label "pipe" $ \(input :: [Int])-> runCoroutine (pipe (putList input) getList) == Just ([], input),
+tests = [label "pipe" $ \(input :: [Int])-> runCoroutine (pipe (putAll input) getAll) == Just ([], input),
          label "pour" prop_pour,
          label "id" prop_id,
          label "suppress" prop_suppress,
@@ -76,25 +80,25 @@
          label "concatenate" prop_concatenate,
          label "concatSeparate" prop_concatSeparate,
          label "uppercase ->>" $ \s-> runCoroutine (pipe
-                                                        (putList s)
+                                                        (putAll s)
                                                         (consume $ with $
-                                                         uppercase >-> atomic "getList" 1 (Consumer getList)))
+                                                         uppercase >-> atomic "getAll" 1 (Consumer getAll)))
                   == Just ([], map toUpper s),
          label "uppercase <<-" $ \s-> runCoroutine (pipe
                                                         (produce $ with $
-                                                         atomic "putList" 1 (Producer (putList s)) >-> uppercase)
-                                                        getList)
+                                                         atomic "putAll" 1 (Producer (putAll s)) >-> uppercase)
+                                                        getAll)
                   == Just ([], map toUpper s),
          label "uppercase `join` id" $ \s-> transducerOutput (uppercase `join` id) s == map toUpper s ++ s,
          label "prepend >-> append" (\(s :: String) prefix suffix->
-                                     transducerOutput (prepend (fromList prefix) >-> append (fromList suffix)) s
+                                     transducerOutput (prepend (produceFrom prefix) >-> append (produceFrom suffix)) s
                                      == prefix ++ s ++ suffix),
          label "prepend == (`join` id) . substitute" $
-               \(s :: String) prefix-> transducerOutput (prepend (fromList prefix)) s
-                                       == transducerOutput (substitute (fromList prefix) `join` id) s,
+               \(s :: String) prefix-> transducerOutput (prepend (produceFrom prefix)) s
+                                       == transducerOutput (substitute (produceFrom prefix) `join` id) s,
          label "append == (id `join`) . substitute" $
-               \(s :: String) suffix-> transducerOutput (append (fromList suffix)) s
-                                       == transducerOutput (id `join` substitute (fromList suffix)) s,
+               \(s :: String) suffix-> transducerOutput (append (produceFrom suffix)) s
+                                       == transducerOutput (id `join` substitute (produceFrom suffix)) s,
          label "whitespace" $ \s-> splitterOutputs whitespace s == (filter isSpace s, filter (not . isSpace) s),
          label "ifs everything id id" $ \(s :: [TestEnum])-> transducerOutput (ifs everything id id) s == s,
          label "substring" $ \s (c :: TestEnum)-> splitterOutputs (substring [c]) s == (filter (==c) s, filter (/=c) s),
@@ -119,7 +123,7 @@
          label "count >-> toString >-> concatenate" $
                \(s :: [TestEnum])-> transducerOutput (count >-> toString >-> concatenate) s == show (length s),
          label "foreach whitespace id (prepend \"[\" >-> append \"]\")" $
-               \s-> transducerOutput (foreach whitespace id (prepend (fromList "[") >-> append (fromList "]"))) s
+               \s-> transducerOutput (foreach whitespace id (prepend (produceFrom "[") >-> append (produceFrom "]"))) s
                     == mapWords (("[" ++) . (++ "]")) s,
          label "foreach whitespace id (count >-> toString >-> concatenate)" $
                \s-> transducerOutput (foreach whitespace id (count >-> toString >-> concatenate)) s
@@ -188,7 +192,7 @@
          label "uptoFirst" $ prop_uptoFirst . splitterFromTrace,
          label "lastAndAfter" $ prop_lastAndAfter . splitterFromTrace,
          label "followedBy prefix" $
-               \trace1 trace2 n-> prop_followedBy1 (splitterFromTrace trace1) (splitterFromTrace trace2) n,
+               \trace1 trace2 n-> prop_followedBy1 (splitterFromTrace trace1) (simplestSplitterFromTrace trace2) n,
          label "followedBy startOf everything" $ \trace n-> prop_followedBy2 (splitterFromTrace trace) n,
          label "substring followedBy substring 1" prop_followedBy3,
          label "substring followedBy substring 2" prop_followedBy4,
@@ -208,26 +212,26 @@
 
 
 prop_pour :: [Int] -> Bool
-prop_pour input = runCoroutine (pipe (putList input) (\source-> pipe (\sink-> pour source sink) getList))
+prop_pour input = runCoroutine (pipe (putAll input) (\source-> pipe (\sink-> pour_ source sink) getAll))
                   == Just ([], ((), input))
 
 prop_id :: [Int] -> Bool
 prop_id input = transducerOutput id input == input
 
 prop_suppress :: [Int] -> Bool
-prop_suppress input = null (transducerOutput (consumeBy suppress :: TransducerComponent Identity Int ()) input)
+prop_suppress input = null (transducerOutput (consumeBy suppress :: TransducerComponent Identity [Int] [()]) input)
 
 prop_substitute :: [Int] -> [Maybe Int] -> Bool
-prop_substitute input replacement = transducerOutput (substitute $ fromList replacement) input == replacement
+prop_substitute input replacement = transducerOutput (substitute $ produceFrom replacement) input == replacement
 
 prop_prepend :: [Int] -> [Int] -> Int -> Property
 prop_prepend input prefix threads = threads > 0 ==>
-                                    transducerOutput (usingThreads (prepend $ fromList prefix) threads) input
+                                    transducerOutput (usingThreads (prepend $ produceFrom prefix) threads) input
                                     == prefix ++ input
 
 prop_append :: [Int] -> [Int] -> Int -> Property
 prop_append input suffix threads = threads > 0 ==>
-                                   transducerOutput (usingThreads (append $ fromList suffix) threads) input
+                                   transducerOutput (usingThreads (append $ produceFrom suffix) threads) input
                                    == input ++ suffix
 
 prop_allTrue :: [Int] -> Bool
@@ -245,9 +249,10 @@
                                       && not (sublist `isInfixOf` (tail sublist ++ init sublist))
                                       ==> classify (not (sublist `isInfixOf` input)) "trivial"
                                              (transducerOutput (parseRegions (substring sublist)) input
-                                              == map unitFromOccurrence (transducerOutput (parseSubstring sublist) input))
-   where unitFromOccurrence (Content x) = Content x
-         unitFromOccurrence (Markup b) = Markup (fmap (const ()) b)
+                                              == concatMap unitFromOccurrence (transducerOutput (parseSubstring sublist) input))
+   where unitFromOccurrence (Content []) = []
+         unitFromOccurrence (Content x) = [Content x]
+         unitFromOccurrence (Markup b) = [Markup (fmap (const ()) b)]
 
 prop_group :: [Int] -> Bool
 prop_group input = transducerOutput group input == [input]
@@ -258,7 +263,7 @@
 prop_concatSeparate :: [[TestEnum]] -> [TestEnum] -> Bool
 prop_concatSeparate input separator = transducerOutput (concatSeparate separator) input == intercalate separator input
 
-prop_snot :: SplitterComponent Identity Int () -> [Int] -> Bool
+prop_snot :: SplitterComponent Identity [Int] -> [Int] -> Bool
 prop_snot splitter input = splitterOutputs (snot splitter) input == swap (splitterOutputs splitter input)
 
 prop_andAssoc :: SplitterTrace -> SplitterTrace -> SplitterTrace -> [Int] -> Int -> Int -> Property
@@ -279,53 +284,53 @@
          s2 = splitterFromTrace st2
          s3 = splitterFromTrace st3
 
-prop_DeMorgan1 :: SplitterComponent Identity Int () -> SplitterComponent Identity Int () -> [Int]
+prop_DeMorgan1 :: SplitterComponent Identity [Int] -> SplitterComponent Identity [Int] -> [Int]
                -> Positive Int -> Positive Int -> Bool
 prop_DeMorgan1 s1 s2 input (Positive t1) (Positive t2)
    = splitterOutputs (usingThreads (snot (s1 C.&& s2)) (t1 `mod` 50)) input
       == splitterOutputs (usingThreads (snot s1 C.|| snot s2) (t2 `mod` 50)) input
 
-prop_DeMorgan2 :: SplitterComponent Identity Int () -> SplitterComponent Identity Int () -> [Int]
+prop_DeMorgan2 :: SplitterComponent Identity [Int] -> SplitterComponent Identity [Int] -> [Int]
                -> Positive Int -> Positive Int -> Bool
 prop_DeMorgan2 s1 s2 input (Positive t1) (Positive t2)
    = splitterOutputs (usingThreads (snot (s1 C.|| s2)) (t1 `mod` 50)) input
      == splitterOutputs (usingThreads (snot s1 C.&& snot s2) (t2 `mod` 50)) input
 
-prop_and :: SplitterComponent Identity Int () -> SplitterComponent Identity Int () -> Positive Int -> Bool
+prop_and :: SplitterComponent Identity [Int] -> SplitterComponent Identity [Int] -> Positive Int -> Bool
 prop_and s1 s2 (Positive n) = fst (splitterOutputs (s1 C.&& s2) l)
                               == fst (splitterOutputs s1 l) `intersect` fst (splitterOutputs s2 l)
    where l = [1 .. n `mod` 1000]
 
-prop_or :: SplitterComponent Identity Int () -> SplitterComponent Identity Int () -> Positive Int -> Bool
+prop_or :: SplitterComponent Identity [Int] -> SplitterComponent Identity [Int] -> Positive Int -> Bool
 prop_or s1 s2 (Positive n) = fst (splitterOutputs (s1 C.|| s2) l)
                              == sort (fst (splitterOutputs s1 l) `union` fst (splitterOutputs s2 l))
    where l = [1 .. n `mod` 1000]
 
-prop_even :: SplitterComponent Identity TestEnum () -> [TestEnum] -> Bool
+prop_even :: SplitterComponent Identity [TestEnum] -> [TestEnum] -> Bool
 prop_even splitter input = let splitOddEven [] = ([], [])
                                splitOddEven (head:tail) = let (evens, odds) = splitOddEven tail in (head:odds, evens)
                            in fst (splitterOutputs (even splitter) input)
                               == concat (snd $ splitOddEven $
                                          transducerOutput (foreach splitter group (consumeBy suppress)) input)
 
-prop_prefix_1 :: SplitterComponent Identity TestEnum () -> [TestEnum] -> Bool
+prop_prefix_1 :: SplitterComponent Identity [TestEnum] -> [TestEnum] -> Bool
 prop_prefix_1 splitter input = let (pfx, rest) = splitterOutputs (prefix splitter) input
                                    (true, false) = splitterOutputs splitter input
                                in pfx ++ rest == input && pfx `isPrefixOf` true
 
-prop_prefix_2 :: SplitterComponent Identity TestEnum () -> [TestEnum] -> Bool
+prop_prefix_2 :: SplitterComponent Identity [TestEnum] -> [TestEnum] -> Bool
 prop_prefix_2 splitter input = let (prefix1, rest1) = splitterOutputs (prefix splitter) input
                                in case splitterOutputChunks splitter input
                                   of (prefix2, True):rest2 -> prefix1 == prefix2 && rest1 == concat (map fst rest2)
                                      (prefix2, False):rest2 -> prefix1 == [] && rest1 == prefix2 ++ concat (map fst rest2)
                                      [] -> prefix1 ++ rest1 == []
 
-prop_suffix_1 :: SplitterComponent Identity TestEnum () -> [TestEnum] -> Bool
+prop_suffix_1 :: SplitterComponent Identity [TestEnum] -> [TestEnum] -> Bool
 prop_suffix_1 splitter input = let (sfx, rest) = splitterOutputs (suffix splitter) input
                                    (true, false) = splitterOutputs splitter input
                                in rest ++ sfx == input && sfx `isSuffixOf` true
 
-prop_suffix_2 :: SplitterComponent Identity TestEnum () -> [TestEnum] -> Bool
+prop_suffix_2 :: SplitterComponent Identity [TestEnum] -> [TestEnum] -> Bool
 prop_suffix_2 splitter input = let (suffix1, rest1) = splitterOutputs (suffix splitter) input
                                in case reverse (splitterOutputChunks splitter input)
                                   of (suffix2, True):rest2 -> suffix1 == suffix2
@@ -334,7 +339,7 @@
                                                                && rest1 == concat (map fst (reverse rest2)) ++ suffix2
                                      [] -> rest1 ++ suffix1 == []
 
-prop_first :: SplitterComponent Identity TestEnum () -> [TestEnum] -> Bool
+prop_first :: SplitterComponent Identity [TestEnum] -> [TestEnum] -> Bool
 prop_first splitter input = let (first1, rest1) = splitterOutputs (first splitter) input
                             in case splitterOutputChunks splitter input
                                of (first2, True):rest2 -> first1 == first2 && rest1 == concat (map fst rest2)
@@ -343,7 +348,7 @@
                                   (prefix, False):[] -> first1 == [] && rest1 == prefix
                                   [] -> first1 ++ rest1 == []
 
-prop_last :: SplitterComponent Identity TestEnum () -> [TestEnum] -> Bool
+prop_last :: SplitterComponent Identity [TestEnum] -> [TestEnum] -> Bool
 prop_last splitter input = let (last1, rest1) = splitterOutputs (last splitter) input
                            in -- trace (show (last1, rest1)) $ trace (show (splitterOutputChunks splitter input)) $
                               case reverse (splitterOutputChunks splitter input)
@@ -353,7 +358,7 @@
                                  (suffix, False):[] -> last1 == [] && rest1 == suffix
                                  [] -> last1 ++ rest1 == []
 
-prop_uptoFirst :: SplitterComponent Identity TestEnum () -> [TestEnum] -> Bool
+prop_uptoFirst :: SplitterComponent Identity [TestEnum] -> [TestEnum] -> Bool
 prop_uptoFirst splitter input = let (first1, rest1) = splitterOutputs (uptoFirst splitter) input
                                 in case splitterOutputChunks splitter input
                                    of (first2, True):rest2 -> first1 == first2 && rest1 == concat (map fst rest2)
@@ -362,7 +367,7 @@
                                       (prefix, False):[] -> first1 == [] && rest1 == prefix
                                       [] -> first1 ++ rest1 == []
 
-prop_lastAndAfter :: SplitterComponent Identity TestEnum () -> [TestEnum] -> Bool
+prop_lastAndAfter :: SplitterComponent Identity [TestEnum] -> [TestEnum] -> Bool
 prop_lastAndAfter splitter input = let (last1, rest1) = splitterOutputs (lastAndAfter splitter) input
                                    in case reverse (splitterOutputChunks splitter input)
                                       of (last2, True):rest2 -> last1 == last2 && rest1 == concat (map fst (reverse rest2))
@@ -371,12 +376,12 @@
                                          (suffix, False):[] -> last1 == [] && rest1 == suffix
                                          [] -> last1 ++ rest1 == []
 
-prop_followedBy1 :: SplitterComponent Identity Int () -> SplitterComponent Identity Int () -> Positive Int -> Bool
+prop_followedBy1 :: SplitterComponent Identity [Int] -> SplitterComponent Identity [Int] -> Positive Int -> Bool
 prop_followedBy1 s1 s2 (Positive n) = splitterOutputs (s1 `followedBy` s2) l
                                       == splitterOutputs (s1 `followedBy` prefix s2) l
    where l = [1 .. n `mod` 300]
 
-prop_followedBy2 :: SplitterComponent Identity Int () -> Int -> Bool
+prop_followedBy2 :: SplitterComponent Identity [Int] -> Int -> Bool
 prop_followedBy2 s n = splitterOutputs (s `followedBy` startOf everything) l == splitterOutputs s l
    where l = [1 .. n `mod` 300]
 
@@ -399,7 +404,7 @@
    in splitterOutputs (substring [n1 .. n2] `followedBy` substring [n2 + 1 .. n3]) [0 .. n4]
          == ([n1 .. n3], [0 .. n1 - 1] ++ [n3 + 1 .. n4])
 
-prop_followedBy6 :: SplitterComponent Identity Int () -> SplitterComponent Identity Int () -> Positive Int -> Bool
+prop_followedBy6 :: SplitterComponent Identity [Int] -> SplitterComponent Identity [Int] -> Positive Int -> Bool
 prop_followedBy6 s1 s2 (Positive n) = sort (fst (splitterOutputs (endOf s1 `followedBy` s2) l)
                                             `union` fst (splitterOutputs (s1 `followedBy` startOf s2) l))
                                       == fst (splitterOutputs (s1 `followedBy` s2) l)
@@ -416,13 +421,13 @@
          [0 .. n4]
       == ([n1 .. n3], [0 .. n1 - 1] ++ [n3 + 1 .. n4])
 
-prop_between1 :: SplitterComponent Identity Int () -> Positive Int -> Bool
+prop_between1 :: SplitterComponent Identity [Int] -> Positive Int -> Bool
 prop_between1 splitter (Positive n) =
    splitterOutputs (startOf splitter ... endOf splitter) input == splitterOutputs splitter input
    && splitterOutputs (endOf splitter ... startOf splitter) input == ([], input)
    where input = [1 .. n `mod` 500]
 
-prop_between2 :: SplitterComponent Identity Int () -> Positive Int -> Bool
+prop_between2 :: SplitterComponent Identity [Int] -> Positive Int -> Bool
 prop_between2 splitter (Positive n) = splitterOutputs (startOf everything ... endOf splitter) input
                                       == splitterOutputs (uptoFirst splitter) input
                                       || null (fst $ splitterOutputs splitter input)
@@ -430,15 +435,16 @@
 
 prop_XMLtokens1 :: [LowercaseLetter] -> String -> Property
 prop_XMLtokens1 name content = name /= [] && intersect content "<&" == []
-                               ==> splitterOutputs xmlTokens (start ++ content ++ end) == (start ++ end, content)
+                               ==> splitterOutputs xmlTokens (fromString $ start ++ content ++ end)
+                                   == (fromString $ start ++ end, fromString content)
    where name' = map letterChar name
          start = "<" ++ name' ++ ">"
          end = "</" ++ name' ++ ">"
 
 prop_XMLtokens2 :: [LowercaseLetter] -> [(Identifier, String)] -> String -> Property
 prop_XMLtokens2 name attrs content = name /= [] && all validAttribute attrs && intersect content "<&" == []
-                                     ==> splitterOutputs xmlTokens (start ++ content ++ end)
-                                            == (start ++ end, content)
+                                     ==> splitterOutputs xmlTokens (fromString $ start ++ content ++ end)
+                                            == (fromString $ start ++ end, fromString content)
    where name' = map letterChar name
          start = "<" ++ name' ++ concatMap attribute attrs ++ ">"
          end = "</" ++ name' ++ ">"
@@ -446,9 +452,9 @@
 prop_XMLtokens3 :: [LowercaseLetter] -> Bool -> [(Identifier, String)] -> String -> Property
 prop_XMLtokens3 name ws attrs content = name /= [] && all validAttribute attrs && intersect content "<&" == []
                                         ==> transducerOutput
-                                               (xmlParseTokens >-> select xmlElementContent >-> unparse >-> coerce)
-                                               (start ++ content ++ end)
-                                               == content
+                                               (xmlParseTokens >-> select xmlElementContent >-> unparse)
+                                               (fromString $ start ++ content ++ end)
+                                               == fromString content
    where name' = map letterChar name ++ spaces
          spaces = if ws then "\n\t  " else ""
          start = "<" ++ name' ++ List.intercalate spaces (map attribute attrs) ++ ">"
@@ -456,7 +462,7 @@
 
 prop_XMLtokens4 :: NonEmptyList LowercaseLetter -> [(Identifier, String)] -> String -> Bool
 prop_XMLtokens4 (NonEmpty name) attrs content =
-   transducerOutput (xmlParseTokens >-> unparse >-> coerce) input == input
+   transducerOutput (xmlParseTokens >-> unparse) (fromString input) == fromString input
    where name' = map letterChar name
          start = "<" ++ name' ++ concatMap attribute attrs ++ ">"
          end = "</" ++ name' ++ ">"
@@ -467,17 +473,20 @@
 prop_nestedInXMLcontent startTagsAndContent = transducerOutput
                                                  (xmlParseTokens
                                                   >-> select (snot xmlElement `nestedIn` xmlElementContent)
-                                                  >-> unparse >-> coerce)
-                                                 (nestXMLelements startTagsAndContent)
-                                              == concatMap escapeContentCharacter (concat (rights startTagsAndContent))
+                                                  >-> unparse)
+                                                 (fromString $ nestXMLelements startTagsAndContent)
+                                              == (fromString $
+                                                  concatMap escapeContentCharacter $
+                                                  concat (rights startTagsAndContent))
 
 prop_whileXMLelement :: [Either (Identifier, [(Identifier, String)]) String] -> Bool
 prop_whileXMLelement startTagsAndContent = transducerOutput
                                               (xmlParseTokens
                                                >-> (select xmlElementContent `while` xmlElement)
-                                               >-> unparse >-> coerce)
-                                              (nestXMLelements startTagsAndContent)
-                                           == concatMap escapeContentCharacter (concat (rights startTagsAndContent))
+                                               >-> unparse)
+                                              (fromString $ nestXMLelements startTagsAndContent)
+                                           == (fromString $
+                                               concatMap escapeContentCharacter (concat (rights startTagsAndContent)))
 
 nestXMLelements [] = []
 nestXMLelements (Left (Identifier (NonEmpty name), attrs) : rest) = "<" ++ name' ++ concatMap attribute attrs ++ ">"
@@ -503,84 +512,96 @@
 escapeContentCharacter '&' = "&amp;"
 escapeContentCharacter x = [x]
 
-uppercaseContent :: (Functor f, Monad m) => TransducerComponent m (f Char) (f Char)
-uppercaseContent = atomic "uppercase" 1 (oneToOneTransducer $ fmap toUpper)
+uppercaseContent :: (Functor f, Monad m) => TransducerComponent m [f String] [f String]
+uppercaseContent = atomic "uppercase" 1 (oneToOneTransducer $ map $ fmap (map toUpper))
 
-transducerOutput :: TransducerComponent Identity x y -> [x] -> [y]
+transducerOutput :: (MonoidNull x, MonoidNull y) => TransducerComponent Identity x y -> x -> y
 transducerOutput t = transducerOutput' (with t)
 
-transducerOutput' :: Transducer Identity x y -> [x] -> [y]
+transducerOutput' :: (MonoidNull x, MonoidNull y) => Transducer Identity x y -> x -> y
 transducerOutput' t input = case runCoroutine (pipe
-                                                   (putList input)
+                                                   (putAll input)
                                                    (\source-> pipe
                                                                  (\sink-> transduce t source sink)
-                                                                 getList))
-                           of Identity (_, (_, output)) -> output
+                                                                 getAll))
+                            of Identity (_, (_, output)) -> output
 
-splitterOutputs :: SplitterComponent Identity x b -> [x] -> ([x], [x])
-splitterOutputs s input = 
+splitterOutputs :: MonoidNull x => SplitterComponent Identity x -> x -> (x, x)
+splitterOutputs s input =
    case runCoroutine (pipe
-                         (putList input)
-                         (\source-> 
+                         (putAll input)
+                         (\source->
                            pipe 
-                              (\true-> 
+                              (\true->
                                 pipe
-                                   (\false-> 
-                                     pipe
-                                        (\edge-> split (with s) source true false edge)
-                                        (mapMStream_ (const $ return ())))
-                                   getList)
-                              getList))
+                                   (split (with s) source true)
+                                   getAll)
+                              getAll))
    of Identity (_, ((_, false), true)) -> (true, false)
 
-splitterUnifiedOutput :: forall x b. SplitterComponent Identity x b -> [x] -> [Either (x, Bool) b]
+splitterUnifiedOutput :: forall x b. SplitterComponent Identity [x] -> [x] -> [(x, Bool)]
 splitterUnifiedOutput s input =
    snd $ runIdentity $
    runCoroutine (pipe
                      (\sink-> pipe
-                                 (putList input)
+                                 (putAll input)
                                  (mapSplit s sink))
-                     getList)
+                     getAll)
    where mapSplit :: forall a d. AncestorFunctor a d =>
-                     SplitterComponent Identity x b -> Sink Identity a (Either (x, Bool) b) -> Source Identity d x
+                     SplitterComponent Identity [x] -> Sink Identity a [(x, Bool)] -> Source Identity d [x]
                   -> Coroutine d Identity ()
-         mapSplit s sink source = let sink' = liftSink sink :: Sink Identity d (Either (x, Bool) b)
+         mapSplit s sink source = let sink' = liftSink sink :: Sink Identity d [(x, Bool)]
                                   in split (with s) source
-                                        (mapSink (Left . (\x-> (x, True))) sink')
-                                        (mapSink (Left . (\x-> (x, False))) sink')
-                                        (mapSink Right sink')
+                                     (mapSink (\x-> (x, True)) sink')
+                                        (mapSink (\x-> (x, False)) sink')
 
-splitterOutputChunks :: SplitterComponent Identity x b -> [x] -> [([x], Bool)]
-splitterOutputChunks s input = transducerOutput (foreach s
-                                                 (group >-> atomic "true" 1 (oneToOneTransducer (\chunk-> (chunk, True))))
-                                                 (group >-> atomic "true" 1 (oneToOneTransducer (\chunk-> (chunk, False)))))
-                               input
+splitterOutputChunks :: SplitterComponent Identity [x] -> [x] -> [([x], Bool)]
+splitterOutputChunks s input = 
+   transducerOutput (foreach s
+                        (group >-> atomic "true" 1 (oneToOneTransducer (\[chunk]-> [(chunk, True)])))
+                        (group >-> atomic "false" 1 (oneToOneTransducer (\[chunk]-> [(chunk, False)]))))
+                    input
 
-simpleSplitterFromTrace :: SimpleSplitterTrace -> SplitterComponent Identity x ()
-simpleSplitterFromTrace (init, last) = splitterFromTrace (fmap Just init, last)
+splitterRawChunks :: SplitterComponent Identity [x] -> [[x]] -> [Maybe ([x], Bool)]
+splitterRawChunks s input =
+   snd $ runIdentity $ runCoroutine $
+   pipe
+      (\sink-> pipe
+         (\sink-> mapM_ (putChunk sink) input)
+         (\source-> pipe
+                       (\true-> pipe
+                                   (split (with s) source true)
+                                   (\source-> mapStreamChunks (\chunk-> [Just (chunk, False)]) source sink))
+                       (\source-> mapStreamChunks (\chunk-> [Just (chunk, True)]) source sink)))
+      getAll
 
-splitterFromTrace :: SplitterTrace -> SplitterComponent Identity x ()
+simplestSplitterFromTrace :: SimplestSplitterTrace -> SplitterComponent Identity [x]
+simplestSplitterFromTrace (init, last) = splitterFromTrace (map (Just . Just) init, last)
+
+simpleSplitterFromTrace :: SimpleSplitterTrace -> SplitterComponent Identity [x]
+simpleSplitterFromTrace (init, last) = splitterFromTrace (map Just init, last)
+
+splitterFromTrace :: SplitterTrace -> SplitterComponent Identity [x]
 splitterFromTrace trace = atomic "splitterFromTrace" 1 (splitterFromTrace' trace)
 
-splitterFromTrace' :: SplitterTrace -> Splitter Identity x ()
+splitterFromTrace' :: SplitterTrace -> Splitter Identity [x]
 splitterFromTrace' trace1
    = Splitter $
-     \source true false edge->
+     \source true false->
      let follow previous trace2@(head:tail) q = get source >>= maybe fail succeed
             where succeed x = let q' = q |> x
                               in case head
                                  of Nothing -> follow previous tail q'
-                                    Just Nothing -> when (not previous) (put edge ())
+                                    Just Nothing -> when (not previous) (putChunk true [] >> return ())
                                                     >> follow False tail q'
-                                    Just (Just True) -> when (not previous) (put edge ())
-                                                        >> putList (Foldable.toList (Seq.viewl q')) true
+                                    Just (Just True) -> when (not previous) (putChunk true [] >> return ())
+                                                        >> putAll (Foldable.toList (Seq.viewl q')) true
                                                         >> follow True tail Seq.empty
-                                    Just (Just False) -> putList (Foldable.toList (Seq.viewl q')) false
+                                    Just (Just False) -> putAll (Foldable.toList (Seq.viewl q')) false
                                                          >> follow False tail Seq.empty
                   fail = if find (maybe False isJust) trace2 == Just (Just (Just True))
-                         then do when (not previous) (put edge ())
-                                 putList (Foldable.toList (Seq.viewl q)) true
-                         else putList (Foldable.toList (Seq.viewl q)) false
+                         then putAll (Foldable.toList (Seq.viewl q)) true
+                         else putAll (Foldable.toList (Seq.viewl q)) false
      in follow False (cycle (fst trace1 ++ [Just (Just $ snd trace1)])) Seq.empty 
         >> return ()
 
@@ -590,8 +611,8 @@
 mapWords :: (String -> String) -> String -> String
 mapWords f s = concat (map (\w@(c:_)-> if isSpace c then w else f w) (groupBy (\x y-> isSpace x == isSpace y) s))
 
+type SimplestSplitterTrace = ([Bool], Bool)
 type SimpleSplitterTrace = ([Maybe Bool], Bool)
-
 type SplitterTrace = ([Maybe (Maybe Bool)], Bool)
 
 data TestEnum = One | Two | Three | Four | Five deriving (Enum, Eq, Show)
@@ -622,10 +643,10 @@
 instance CoArbitrary c => CoArbitrary (Component c) where
    coarbitrary c = coarbitrary (with c)
 
-instance Arbitrary (Splitter Identity Int ()) where
+instance Arbitrary (Splitter Identity [Int]) where
    arbitrary = fmap splitterFromTrace' arbitrary
-instance CoArbitrary (Splitter Identity Int ()) where
+instance CoArbitrary (Splitter Identity [Int]) where
    coarbitrary s gen = sized (\n-> coarbitrary (transducerOutput' (Combinator.ifs sequentialBinder s
-                                                                   (oneToOneTransducer $ const True)
-                                                                   (oneToOneTransducer $ const False))
+                                                                   (oneToOneTransducer $ const [True])
+                                                                   (oneToOneTransducer $ const [False]))
                                                 [1..n]) gen)
diff --git a/scc.cabal b/scc.cabal
--- a/scc.cabal
+++ b/scc.cabal
@@ -1,15 +1,15 @@
 Name:                scc
-Version:             0.7.1
-Cabal-Version:       >= 1.2
+Version:             0.8
+Cabal-Version:       >= 1.10
 Build-Type:          Simple
 Synopsis:            Streaming component combinators
 Category:            Control, Combinators, Concurrency
-Tested-with:         GHC == 6.12.3, GHC == 7.0
+Tested-with:         GHC == 7.4, GHC == 7.6
 Description:
-  SCC is a layered library of Streaming Component Combinators. The lowest layer defines stream abstractions and nested
-  producer-consumer coroutine pairs based on the Coroutine monad transformer. On top of that are streaming component
-  types, a number of primitive streaming components and a set of component combinators. Finally, there is an executable
-  that exposes all the framework functionality in a command-line shell.
+  SCC is a layered library of Streaming Component Combinators. The lowest layer in "Control.Concurent.SCC.Streams"
+  defines stream abstractions and nested producer-consumer coroutine pairs based on the Coroutine monad transformer.
+  On top of that are streaming component types, a number of primitive streaming components and a set of component
+  combinators. Finally, there is an executable that exposes all the framework functionality in a command-line shell.
   .
   The original library design is based on paper <http://conferences.idealliance.org/extreme/html/2006/Blazevic01/EML2006Blazevic01.html>
   .
@@ -17,14 +17,14 @@
 
 License:             GPL
 License-file:        LICENSE.txt
-Copyright:           (c) 2008-2011 Mario Blazevic
+Copyright:           (c) 2008-2013 Mario Blazevic
 Author:              Mario Blazevic
 Maintainer:          blamario@yahoo.com
 Homepage:            http://trac.haskell.org/SCC/
 Extra-source-files:  grammar.bnf Makefile
--- Source-repository head
---   type:              darcs
---   location:          http://code.haskell.org/SCC/
+Source-repository head
+  type:              darcs
+  location:          http://code.haskell.org/SCC/
 Flag Test
   Description: Install QuickCheck test suite
   Default:     False
@@ -34,31 +34,42 @@
   Other-Modules:     Control.Concurrent.SCC.Streams, Control.Concurrent.SCC.Types, Control.Concurrent.SCC.Coercions,
                      Control.Concurrent.SCC.Combinators, Control.Concurrent.SCC.Primitives, Control.Concurrent.SCC.XML,
                      Control.Concurrent.Configuration, Control.Concurrent.SCC.Configurable
-  Build-Depends:     base < 5, containers, transformers >= 0.2 && < 0.3, incremental-parser >= 0.2 && < 0.3,
-                     monad-parallel, monad-coroutine >= 0.7 && < 0.8, bytestring < 1.0, text < 1.0,
-                     process, readline, parsec >= 3.0 && < 4.0
+  Build-Depends:     base < 5, containers, transformers >= 0.2 && < 0.4, bytestring < 1.0, text < 1.0,
+                     monoid-subclasses == 0.1.*, incremental-parser >= 0.2.2 && < 0.3,
+                     monad-parallel, monad-coroutine == 0.8.*,
+                     process, haskeline, parsec == 3.*
   GHC-options:       -threaded
+  if impl(ghc >= 7.0.0)
+     default-language: Haskell2010
 
-Executable test-scc
+test-suite Main
+  Type:              exitcode-stdio-1.0
+  x-uses-tf:         true
   Main-is:           Test/TestSCC.hs
   Other-Modules:     Control.Concurrent.SCC.Streams, Control.Concurrent.SCC.Types, Control.Concurrent.SCC.Coercions,
                      Control.Concurrent.SCC.Combinators, Control.Concurrent.SCC.Primitives,
                      Control.Concurrent.SCC.XML,
                      Control.Concurrent.Configuration, Control.Concurrent.SCC.Configurable
-  Build-Depends:     base < 5, containers, transformers >= 0.2 && < 0.3, incremental-parser >= 0.2 && < 0.3,
-                     monad-parallel, monad-coroutine >= 0.7 && < 0.8, bytestring < 1.0, text < 1.0,
-                     QuickCheck >= 2 && < 3
+  Build-Depends:     base < 5, containers, transformers >= 0.2 && < 0.4, bytestring < 1.0, text < 1.0,
+                     monoid-subclasses == 0.1.*, incremental-parser >= 0.2.2 && < 0.3,
+                     monad-parallel, monad-coroutine == 0.8.*,
+                     QuickCheck >= 2 && < 3, test-framework >= 0.4.1, test-framework-quickcheck2
   GHC-options:       -threaded -fcontext-stack=30
   if !flag(test)
     buildable:       False
+  if impl(ghc >= 7.0.0)
+     default-language: Haskell2010
 
 Library
-  Exposed-Modules:   Control.Concurrent.Configuration, Control.Concurrent.SCC.Configurable,
+  Exposed-Modules:   Control.Concurrent.SCC.Streams, Control.Concurrent.SCC.Types,
+                     Control.Concurrent.SCC.Configurable,
                      Control.Concurrent.SCC.Parallel, Control.Concurrent.SCC.Sequential
-  Other-Modules:     Control.Concurrent.SCC.Streams, Control.Concurrent.SCC.Types, Control.Concurrent.SCC.Coercions,
+  Other-Modules:     Control.Concurrent.Configuration, Control.Concurrent.SCC.Coercions,
                      Control.Concurrent.SCC.Combinators.Parallel, Control.Concurrent.SCC.Combinators.Sequential,
                      Control.Concurrent.SCC.Combinators, Control.Concurrent.SCC.Primitives, Control.Concurrent.SCC.XML
-                     
-  Build-Depends:     base < 5, containers, transformers >= 0.2 && < 0.3, incremental-parser >= 0.2 && < 0.3,
-                     monad-parallel, monad-coroutine >= 0.7 && < 0.8, bytestring < 1.0, text < 1.0
+  Build-Depends:     base < 5, containers, transformers >= 0.2 && < 0.4, bytestring < 1.0, text < 1.0,
+                     monoid-subclasses == 0.1.*, incremental-parser >= 0.2.2 && < 0.3,
+                     monad-parallel, monad-coroutine == 0.8.*
   GHC-prof-options:  -auto-all
+  if impl(ghc >= 7.0.0)
+     default-language: Haskell2010
