diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,5 +1,5 @@
-Copyright (c) 2012-2012, Paolo Capriotti
-Copyright (c) 2012-, Renzo Carbonara
+Copyright (c) 2012-2013, Renzo Carbonara
+Copyright (c) 2012, Paolo Capriotti
 
 All rights reserved.
 
diff --git a/NEWS b/NEWS
new file mode 100644
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,8 @@
+# Version 0.2.0.0
+
+* Droped the previous API in favour of a new and incompatible API
+  that supports interleaved parsing by relying on pipes-parse.
+
+# Version 0.1.0.1
+
+* First version mentioned in NEWS file.
diff --git a/PEOPLE b/PEOPLE
new file mode 100644
--- /dev/null
+++ b/PEOPLE
@@ -0,0 +1,6 @@
+The following people have participated in creating this library, either
+by directly contributing code or by providing thoughtful input in
+discussions about the library design.
+
+Renzo Carbonara
+Gabriel Gonzalez
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,5 +1,12 @@
 # pipes-attoparsec
 
-Utilities to convert an Attoparsec Parser into a Pipe.
+Utilities to run **Attoparsec** parser on **Pipes** input streams.
 
-Version 0.1.\* is not backwards compatible with previous versions.
+Check the source or rendered Haddocks for documentation.
+
+This code is licensed under the terms of the so called **3-clause BSD
+license**. Read the file named ``LICENSE`` found in this same directory
+for details.
+
+See the ``PEOPLE`` file to learn about the people involved in this
+effort.
diff --git a/pipes-attoparsec.cabal b/pipes-attoparsec.cabal
--- a/pipes-attoparsec.cabal
+++ b/pipes-attoparsec.cabal
@@ -1,29 +1,24 @@
-name: pipes-attoparsec
-version: 0.1.0.1
-license: BSD3
-license-file: LICENSE
-copyright: Copyright (c) Paolo Capriotti 2012-2012,
-                         Renzo Carbonara 2012-
-author: Paolo Capriotti, Renzo Carbonara
-maintainer: renzocarbonaraλgmail.com
-stability: Experimental
-tested-with: GHC ==7.4.1, GHC ==7.6.1
-homepage: https://github.com/k0001/pipes-attoparsec
-bug-reports: https://github.com/k0001/pipes-attoparsec
-category: Pipes, Parser
-build-type: Simple
-cabal-version: >=1.8
-synopsis: Utilities to convert an Attoparsec parser into a pipe Pipe.
+name:               pipes-attoparsec
+version:            0.2.0.0
+license:            BSD3
+license-file:       LICENSE
+copyright:          Copyright (c) Renzo Carbonara 2012-2013, Paolo Capriotti 2012
+author:             Renzo Carbonara
+maintainer:         renzocarbonaraλgmail.com
+stability:          Experimental
+tested-with:        GHC ==7.4.1
+homepage:           https://github.com/k0001/pipes-attoparsec
+bug-reports:        https://github.com/k0001/pipes-attoparsec/issues
+category:           Pipes, Parser
+build-type:         Simple
+cabal-version:      >=1.8
+synopsis:           Attoparsec and Pipes integration.
+extra-source-files: README.md PEOPLE NEWS
 description:
-  Utilities to convert an Attoparsec 'Data.Attoparsec.Types.Parser' into
-  a 'Control.Proxy.Synonym.Pipe'.
-  .
-  See "Control.Proxy.Attoparsec.Tutorial" for an extensive introduction with
-  examples.
+  Utilities to run @attoparsec@ parsers on @pipes@ input streams.
   .
-  Version 0.1.* is not backwards compatible with previous versions.
-extra-source-files:
-  README.md
+  See the @NEWS@ file in the source distribution to learn about any
+  important changes between version.
 
 source-repository head
     type: git
@@ -32,36 +27,35 @@
 library
   hs-source-dirs:  src
   exposed-modules: Control.Proxy.Attoparsec
-                   Control.Proxy.Attoparsec.Control
-                   Control.Proxy.Attoparsec.Tutorial
-                   Control.Proxy.Attoparsec.Types
+                   Control.Proxy.Attoparsec.Internal
   build-depends:
-    base (==4.*),
-    pipes (>=3.0),
-    attoparsec (>=0.10),
-    bytestring,
-    text
-
-  ghc-options:
-    -Wall -fno-warn-missing-signatures
+      base         (==4.*)
+    , pipes        (>=3.3 && <3.4)
+    , pipes-parse  (>=1.0 && <1.1)
+    , attoparsec   (>=0.10 && <0.11)
+    , bytestring   (>=0.9.2.1)
+    , text
+    , transformers (>=0.2 && <=0.4)
+  ghc-options: -Wall -O2
 
 test-suite tests
   type:           exitcode-stdio-1.0
   hs-source-dirs: tests
   main-is:        Main.hs
   other-modules:  Test.Attoparsec
-                  Test.Tutorial
-  ghc-options:
-    -Wall -rtsopts -fno-warn-missing-signatures
+  ghc-options: -Wall -rtsopts -fno-warn-missing-signatures
 
   build-depends:
-    base (== 4.*),
-    pipes (>= 3.0),
-    attoparsec (>= 0.10),
-    text,
-    pipes-attoparsec,
-    QuickCheck (== 2.*),
-    HUnit (== 1.*),
-    test-framework (>= 0.6),
-    test-framework-quickcheck2 (>= 0.2),
-    test-framework-hunit (>= 0.2)
+      base
+    , mmorph
+    , pipes
+    , attoparsec
+    , text
+    , pipes-attoparsec
+    , pipes-parse
+    , QuickCheck                 (== 2.*)
+    , HUnit                      (== 1.*)
+    , test-framework             (>= 0.6)
+    , test-framework-quickcheck2 (>= 0.2)
+    , test-framework-hunit       (>= 0.2)
+
diff --git a/src/Control/Proxy/Attoparsec.hs b/src/Control/Proxy/Attoparsec.hs
--- a/src/Control/Proxy/Attoparsec.hs
+++ b/src/Control/Proxy/Attoparsec.hs
@@ -1,94 +1,117 @@
--- | This module provides utilities to turn your Attoparsec @'Parser' a
--- b@ into a 'Pipe' that parses @a@ values into @b@ values as they flow
--- downstream.
+-- | This module allows you to run Attoparsec parsers on input flowing
+-- downstream through Pipes streams, possibly interleaving other stream
+-- effects.
 --
--- See "Control.Proxy.Attoparsec.Tutorial" for an extensive introduction
--- with examples.
+-- This module builds on top of the @pipes-parse@ package and assumes
+-- you have read "Control.Proxy.Parse.Tutorial".
 
 module Control.Proxy.Attoparsec
-  ( -- * Parsing Pipe
-    -- $pieces
-    parserInputD
-  , parserD
-    -- * Modules
-  , module Control.Proxy.Attoparsec.Types
-  , module Control.Proxy.Attoparsec.Control
+  ( -- * Parsing
+    -- $parsing
+    parse
+  , parseD
+  , isEndOfParserInput
+    -- * Types
+  , I.ParserInput(I.null)
+  , I.ParsingError(..)
   ) where
 
-import           Control.Proxy
-import           Control.Proxy.Attoparsec.Control
-import           Control.Proxy.Attoparsec.Types
-import           Data.Attoparsec.Types            (IResult (..), Parser)
-import           Prelude                          hiding (length, null)
+--------------------------------------------------------------------------------
 
+import           Control.Monad                     (unless)
+import qualified Control.Proxy                     as P
+import qualified Control.Proxy.Parse               as Pa
+import qualified Control.Proxy.Attoparsec.Internal as I
+import qualified Control.Proxy.Trans.Either        as P
+import qualified Control.Proxy.Trans.State         as P
+import           Data.Attoparsec.Types             (Parser)
+import           Data.Foldable                     (mapM_)
+import           Data.Function                     (fix)
+import           Prelude                           hiding (mapM_)
 
--- $pieces
+--------------------------------------------------------------------------------
+-- $parsing
 --
--- A 'Pipe' that parses @a@ input flowing downstream into @b@ values is
--- made of at least two smaller cooperating 'Proxy's:
+-- There are two basic parsing facilities exported by this module, and choosing
+-- between them is easy: If you need to interleave Attoparsec parsing with other
+-- stream effects you must use 'parse', otherwise you may use the simpler
+-- 'parseD'.
 --
---  1. 'parserInputD': Prepares @a@ input received from upstream to be
---     consumed by a downstream parsing 'Proxy'.
+-- These proxies use the 'P.EitherP' proxy transformer to report parsing errors,
+-- you might use any of the facilities exported by "Control.Proxy.Trans.Either"
+-- to recover from them.
+
+
+-- | Parses one element flowing downstream.
 --
---  2. 'parserD': Repeatedly runs a given @'Parser' a b@ on input 'a'
---     from upstream, and sends 'b' values downstream.
+-- * In case of parsing errors, a 'I.ParsingError' exception is thrown in
+-- the 'Pe.EitherP' proxy transformer.
 --
--- Given a @'Parser' a b@ named @myParser@, the simplest way to use
--- these 'Proxy's together is:
+-- * Requests more input from upstream using 'Pa.draw' when needed.
 --
--- > myParsingPipe :: (Proxy p, Monad m, AttoparsecInput a) => Pipe a b m r
--- > myParsingPipe = parserInputD >-> parserD myParser
+-- * /Do not/ use this proxy if 'isEndOfParserInput' returns 'True',
+-- otherwise you may get unexpected parsing errors.
 --
--- In between these two 'Proxy's, you can place other 'Proxy's to handle
--- extraordinary situations like parsing failures or limiting input
--- length. "Control.Proxy.Attoparsec.Control" exports some useful
--- 'Proxy's that fit this place. If you skip using any of those, the
--- default behavior is that of
--- 'Control.Proxy.Attoparsec.Control.skipMalformedChunks': to simply
--- ignore all parsing errors and malformed input, and start parsing new
--- input as soon as it's available.
-
-
-
--- | 'Proxy' turning 'a' values flowing downstream into
--- @'ParserSupply' a@ values to be consumed by a downstream parsing
--- 'Proxy'.
+-- Here is an example parsing loop that allows interleaving stream effects
+-- together with 'parse':
 --
--- This 'Proxy' responds with @'Resume' a@ to any 'ParserStatus' value
--- received from downstream.
-parserInputD :: (Monad m, Proxy p)
-             => ParserStatus a -> p () a (ParserStatus a) (ParserSupply a) m r
-parserInputD _ = runIdentityP . forever $ request () >>= respond . (,) Resume
+-- > loop = do
+-- >     eof <- liftP isEndOfParserInput
+-- >     unless eof $ do
+-- >         -- 1. Possibly perform some stream effects here.
+-- >         -- 2. Parse one element from the stream.
+-- >         exampleElement <- parse myExampleParser
+-- >         -- 3. Do something with exampleElement and possibly perform
+-- >         --    some more stream effects.
+-- >         -- 4. Start all over again.
+-- >         loop
+parse
+  :: (I.ParserInput a, Monad m, P.Proxy p)
+  => Parser a r -- ^Attoparsec parser to run on the input stream.
+  -> P.EitherP I.ParsingError (P.StateP [a] p) () (Maybe a) y' y m r
+    -- ^Proxy compatible with the facilities provided by "Control.Proxy.Parse".
+parse parser = do
+    (er, mlo) <- P.liftP (I.parseWithMay Pa.draw parser)
+    P.liftP (mapM_ Pa.unDraw mlo)
+    either P.throw return er
+{-# INLINABLE parse #-}
 
 
--- | 'Proxy' using the given @'Parser' a b@ to repeatedly parse pieces
--- of @'ParserSupply' a@ values flowing downstream into @b@ values.
+-- | Parses consecutive elements flowing downstream until end of input.
 --
--- When more input is needed, a @'ParserStatus' a@ value reporting the
--- current parsing status is sent upstream, and in exchange a
--- @'ParserSupply' a@ value is expected, containing more input to be
--- parsed and directives on how to use it (see 'ParserSupply'
--- documentation).
-parserD :: (Proxy p, Monad m, AttoparsecInput a)
-        => Parser a b
-        -> () -> p (ParserStatus a) (ParserSupply a) () b m r
-parserD parser () = runIdentityP . forever $ ask k0 0 (Parsing 0)
+-- * In case of parsing errors, a 'I.ParsingError' exception is thrown in the
+-- 'Pe.EitherP' proxy transformer.
+--
+-- * Requests more input from upstream using 'Pa.draw' when needed.
+--
+-- * Empty input chunks flowing downstream will be discarded.
+parseD
+  :: (I.ParserInput a, Monad m, P.Proxy p)
+  => Parser a b -- ^Attoparsec parser to run on the input stream.
+  -> () -> P.Pipe (P.EitherP I.ParsingError (P.StateP [a] p)) (Maybe a) b m ()
+    -- ^Proxy compatible with the facilities provided by "Control.Proxy.Parse".
+parseD parser = \() -> loop
   where
-    k0 = parse parser
-
-    requestNonEmpty status = go where
-      go = do
-        ps@(_, chunk) <- request status
-        if null chunk then go else return ps
-
-    ask k len status = do
-      (su, chunk) <- requestNonEmpty status
-      case su of
-        Start  -> use (k0 chunk) 0
-        Resume -> use (k  chunk) (len + length chunk)
+    loop = do
+        eof <- P.liftP isEndOfParserInput
+        unless eof $ do
+          () <- P.respond =<< parse parser
+          loop
+{-# INLINABLE parseD #-}
 
-    use (Partial k)         len = ask k  len $ Parsing len
-    use (Fail rest ctx msg) _   = ask k0 0   $ Failed rest (ParserError ctx msg)
-    use (Done rest result)  _   = respond result >> use (k0 rest) 0
+--------------------------------------------------------------------------------
 
+-- | Like 'Pa.isEndOfInput', except it also consumes and discards leading
+-- empty 'I.ParserInput' chunks.
+isEndOfParserInput
+  :: (I.ParserInput a, Monad m, P.Proxy p)
+  => P.StateP [a] p () (Maybe a) y' y m Bool
+isEndOfParserInput = fix $ \loop -> do
+    ma <- Pa.draw
+    case ma of
+      Just a
+       | I.null a  -> loop
+       | otherwise -> Pa.unDraw a >> return False
+      Nothing      -> return True
+{-# INLINABLE isEndOfParserInput #-}
 
diff --git a/src/Control/Proxy/Attoparsec/Control.hs b/src/Control/Proxy/Attoparsec/Control.hs
deleted file mode 100644
--- a/src/Control/Proxy/Attoparsec/Control.hs
+++ /dev/null
@@ -1,80 +0,0 @@
--- | This module exports some useful 'Proxy's that act upon
--- 'ParserStatus' values received from downstream.
-
-module Control.Proxy.Attoparsec.Control
-  ( skipMalformedChunks
-  , retryLeftovers
-  , throwParsingErrors
-  , limitInputLength
-  ) where
-
-import           Control.Proxy
-import           Control.Proxy.Attoparsec.Types
-import qualified Control.Proxy.Trans.Either as PE
-import           Prelude                    hiding (drop, null)
-
--- | If a downstream parsing 'Proxy' reports a parser failure, skip the
--- whole input /chunk/ being processed, including any left-overs, and
--- start processing new input as soon as it's available.
---
--- Useful when the input found in a single @'ParserSupply' a@ is
--- supposed to be well-formed, so it can be safely skipped if it is not.
-skipMalformedChunks
-  :: (Monad m, Proxy p, AttoparsecInput a)
-  => ParserStatus a
-  -> p (ParserStatus a) (ParserSupply a) (ParserStatus a) (ParserSupply a) m r
-skipMalformedChunks = runIdentityK . foreverK $ go
-  where go x@(Failed _ _) = request x >>= \(_,a) -> respond (Start, a)
-        go x              = request x >>= respond
-
-
--- | If a downstream parsing 'Proxy' reports a parsing failure, then
--- keep retrying with any left-over input, skipping individual bits each
--- time. If there are no left-overs, then more input is requestsd form
--- upstream.
-retryLeftovers
-  :: (Monad m, Proxy p, AttoparsecInput a)
-  => ParserStatus a
-  -> p (ParserStatus a) (ParserSupply a) (ParserStatus a) (ParserSupply a) m r
-retryLeftovers = runIdentityK . foreverK $ go
-  where
-    go s@(Failed _ _) = retry s >>= moreSupply >>= respond
-    go s              = request s >>= respond
-
-    retry s@(Failed rest _) = do
-      s' <- respond (Start, rest)
-      if s' == s then return s
-                 else retry s'
-    retry s = return s
-
-    moreSupply s@(Failed rest _) = do
-      let rest' = drop 1 rest
-      if null rest'
-        then request s
-        else return (Start, rest')
-    moreSupply s = request s
-
-
--- | If a downstream parsing 'Proxy' reports a parser failure, then
--- throw a 'MalformedInput' error in the 'EitherP' proxy transformer.
-throwParsingErrors
-  :: (Monad m, Proxy p, AttoparsecInput a)
-  => ParserStatus a
-  -> PE.EitherP BadInput p (ParserStatus a) (ParserSupply a) (ParserStatus a) (ParserSupply a) m r
-throwParsingErrors = foreverK go
-  where go (Failed _ e) = PE.throw $ MalformedInput e
-        go x            = request x >>= respond
-
-
--- | If a downstream parsing 'Proxy' doesn't produce a value after
--- having consumed input of at least the given length, then throw an
--- 'InputTooLong' error in the 'EitherP' proxy transformer.
-limitInputLength
-  :: (Monad m, Proxy p, AttoparsecInput a)
-  => Int
-  -> ParserStatus a
-  -> PE.EitherP BadInput p (ParserStatus a) (ParserSupply a) (ParserStatus a) (ParserSupply a) m r
-limitInputLength n = foreverK go
-  where go (Parsing m) | m >= n = PE.throw $ InputTooLong m
-        go x                    = request x >>= respond
-
diff --git a/src/Control/Proxy/Attoparsec/Internal.hs b/src/Control/Proxy/Attoparsec/Internal.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Proxy/Attoparsec/Internal.hs
@@ -0,0 +1,108 @@
+{-# LANGUAGE DeriveDataTypeable #-}
+{-# OPTIONS_HADDOCK hide prune #-}
+
+-- | This module provides low-level integration with Attoparsec and is likely
+-- to be modified in backwards-incompatible ways in the future.
+--
+-- Use the stable API exported by the "Control.Proxy.Attoparsec" module instead.
+
+module Control.Proxy.Attoparsec.Internal
+  ( -- * Types
+    ParsingError(..)
+  , ParserInput(..)
+    -- * Parsing
+  , parseWith
+  , parseWithMay
+    -- * Utils
+  , mayInput
+  ) where
+
+--------------------------------------------------------------------------------
+
+import           Control.Exception                 (Exception)
+import           Data.Attoparsec.Types             (Parser, IResult(..))
+import qualified Data.Attoparsec.ByteString        as AB
+import qualified Data.Attoparsec.Text              as AT
+import qualified Data.ByteString.Char8             as B
+import           Data.Data                         (Data, Typeable)
+import           Data.Monoid                       (Monoid(mempty))
+import qualified Data.Text                         as T
+import           Prelude                           hiding (null)
+
+--------------------------------------------------------------------------------
+
+-- | A parsing error report, as provided by Attoparsec's 'Fail'.
+data ParsingError = ParsingError
+  { peContexts :: [String]  -- ^ Contexts where the parsing error occurred.
+  , peMessage  :: String    -- ^ Parsing error description message.
+  } deriving (Show, Eq, Data, Typeable)
+
+instance Exception ParsingError where
+
+--------------------------------------------------------------------------------
+
+-- | A class for valid Attoparsec input types: strict 'T.Text' and
+-- strict 'B.ByteString'.
+class (Monoid a) => ParserInput a where
+    -- | Run a 'Parser' with input @a@.
+    parse :: Parser a b -> a -> IResult a b
+    -- | Tests whether @a@ is empty.
+    null :: a -> Bool
+
+instance ParserInput B.ByteString where
+    parse      = AB.parse
+    null       = B.null
+
+instance ParserInput T.Text where
+    parse      = AT.parse
+    null       = T.null
+
+--------------------------------------------------------------------------------
+
+-- | Run a parser drawing input from the given monadic action as needed.
+parseWith
+  :: (Monad m, ParserInput a)
+  => m a
+  -- ^An action that will be executed to provide the parser with more input
+  -- as needed. If the action returns 'mempty', then it's assumed no more
+  -- input is available.
+  -> Parser a r
+  -- ^Parser to run on the given input
+  -> m (Either ParsingError r, Maybe a)
+  -- ^Either a parser error or a parsed result, together with any leftover.
+parseWith refill p = step . parse p =<< refill where
+    step (Partial k)  = step . k =<< refill
+    step (Done t r)   = return (Right r, mayInput t)
+    step (Fail t c m) = return (Left (ParsingError c m), mayInput t)
+{-# INLINABLE parseWith #-}
+
+
+-- | Run a parser drawing input from the given monadic action as needed.
+parseWithMay
+  :: (Monad m, ParserInput a)
+  => m (Maybe a)
+  -- ^An action that will be executed to provide the parser with more input
+  -- as needed. If the action returns 'Nothing', then it's assumed no more
+  -- input is available. @'Just' 'mempty'@ input is discarded.
+  -> Parser a r
+  -- ^Parser to run on the given input
+  -> m (Either ParsingError r, Maybe a)
+  -- ^Either a parser error or a parsed result, together with any leftover.
+parseWithMay refill p = parseWith loop p
+  where
+    loop = do
+        ma <- refill
+        case ma of
+          Just a
+           | null a    -> loop  -- retry on null input
+           | otherwise -> return a
+          Nothing      -> return mempty
+{-# INLINABLE parseWithMay #-}
+
+
+-- | Wrap @a@ in 'Just' if not-null. Otherwise, 'Nothing'.
+mayInput :: ParserInput a => a -> Maybe a
+mayInput = \x -> if null x then Nothing else Just x
+{-# INLINABLE mayInput #-}
+
+
diff --git a/src/Control/Proxy/Attoparsec/Tutorial.lhs b/src/Control/Proxy/Attoparsec/Tutorial.lhs
deleted file mode 100644
--- a/src/Control/Proxy/Attoparsec/Tutorial.lhs
+++ /dev/null
@@ -1,344 +0,0 @@
-> {-# LANGUAGE OverloadedStrings #-}
-
-| In this tutorial you will learn how to use this library. The /Simple example/
-section should be enough to get you going, but you can keep reading if you want
-to better understand how to deal with complex parsing scenarios.
-
-You may import this module and try the subsequent examples as you go.
-
-
-> module Control.Proxy.Attoparsec.Tutorial
->   (-- * Simple example
->    -- $example-simple
->
->    -- * Parsing control proxies
->    -- ** Handling parser errors
->    -- $example-errors
->
->    -- ** Composing
->    -- $example-compose-control
->
->    -- ** Custom behavior
->    -- $example-control-custom
->
->    -- * Try for yourself
->    -- $example-try
->     Name(..)
->   , hello
->   , input1
->   , input2
->   , helloPipe1
->   , helloPipe2
->   , helloPipe3
->   , helloPipe4
->   , helloPipe5
->   , helloPipe6
->   , skipPartialResults
->   ) where
->
-> import Control.Proxy
-> import Control.Proxy.Attoparsec
-> import Control.Proxy.Trans.Either
-> import Data.Attoparsec.Text
-> import Data.Text
->
-> data Name = Name Text
->           deriving (Show, Eq)
->
-> hello :: Parser Name
-> hello = fmap Name $ "Hello " .*> takeWhile1 (/='.') <*. "."
->
-> input1 :: [Text]
-> input1 =
->   [ "Hello Kate."
->   , "Hello Mary.Hello Jef"
->   , "f."
->   , "Hel"
->   , "lo Tom."
->   ]
->
-> input2 :: [Text]
-> input2 =
->   [ "Hello Amy."
->   , "Hello, Hello Tim."
->   , "Hello Bob."
->   , "Hello James"
->   , "Hello"
->   , "Hello World."
->   , "HexHello Jon."
->   , "H"
->   , "ello Ann"
->   , "."
->   , "Hello Jean-Luc."
->   ]
->
-> helloPipe1 :: (Proxy p, Monad m) => () -> Pipe p Text Name m r
-> helloPipe1 = parserInputD >-> parserD hello
->
-> helloPipe2 :: (Proxy p, Monad m) => () -> Pipe p Text Name m r
-> helloPipe2 = parserInputD >-> retryLeftovers >-> parserD hello
->
-> helloPipe3 :: (Proxy p, Monad m) => () -> Pipe (EitherP BadInput p) Text Name m r
-> helloPipe3 = parserInputD >-> throwParsingErrors >-> parserD hello
->
-> helloPipe4 :: (Proxy p, Monad m) => () -> Pipe (EitherP BadInput p) Text Name m r
-> helloPipe4 = parserInputD >-> limitInputLength 10 >-> parserD hello
->
-> helloPipe5 :: (Proxy p, Monad m) => () -> Pipe (EitherP BadInput p) Text Name m r
-> helloPipe5 = parserInputD >-> limitInputLength 10 >-> retryLeftovers >-> parserD hello
->
-> helloPipe6 :: (Proxy p, Monad m) => () -> Pipe p Text Name m r
-> helloPipe6 = parserInputD >-> skipPartialResults >-> parserD hello
->
-> skipPartialResults
->  :: (Monad m, Proxy p, AttoparsecInput a)
->  => ParserStatus a
->  -> p (ParserStatus a) (ParserSupply a) (ParserStatus a) (ParserSupply a) m r
-> skipPartialResults = runIdentityK . foreverK $ go
->   where go x@(Parsing _) = request x >>= \(_, a) -> respond (Start, a)
->         go x             = request x >>= respond
-
-
-$example-simple
-
-We'll write a simple 'Parser' that turns 'Text' like /“Hello John Doe.”/
-into @'Name' \"John Doe\"@, and then make a 'Pipe' that turns
-those 'Text' values flowing downstream into 'Name' values flowing
-downstream using that 'Parser'.
-
-In this example we are using 'Text', but we may as well use
-'Data.ByteString.ByteString'. Also, the 'OverloadedStrings' language
-extension lets us write our parser easily.
-
-  > {-# LANGUAGE OverloadedStrings #-}
-  >
-  > import Control.Proxy
-  > import Control.Proxy.Attoparsec
-  > import Control.Proxy.Trans.Either
-  > import Data.Attoparsec.Text
-  > import Data.Text
-  >
-  > data Name = Name Text
-  >           deriving (Show)
-  >
-  > hello :: Parser Name
-  > hello = fmap Name $ "Hello " .*> takeWhile1 (/='.') <*. "."
-
-We are done with our parser, now lets make a simple parsing 'Pipe' with it.
-
-  > helloPipe1 :: (Proxy p, Monad m) => () -> Pipe p Text Name m r
-  > helloPipe1 = parserInputD >-> parserD hello
-
-As the type indicates, this 'Pipe' receives 'Text' values from upstream and
-sends 'Name' values downstream. This 'Pipe' is made of two smaller
-two smaller cooperating 'Proxy's:
-
-  1. 'parserInputD': Prepares @a@ input received from upstream to be
-     consumed by a downstream parsing 'Proxy'.
-
-  2. 'parserD': Repeatedly runs a given @'Parser' a b@ on input 'a' from
-     upstream, and sends 'b' values downstream.
-
-We need some sample input to test our simple 'helloPipe1'.
-
-  > input1 :: [Text]
-  > input1 =
-  >   [ "Hello Kate."
-  >   , "Hello Mary.Hello Jef"
-  >   , "f."
-  >   , "Hel"
-  >   , "lo Tom."
-  >   ]
-
-We'll use @'fromListS' input1@ as our input source, which sends
-downstream one element from the list at a time. We'll call each of these
-elements a /chunk/. So, @'fromListS' input1@ sends 5 /chunks/ of
-'Text' downstream.
-
-Notice how some of our /chunks/ are not, by themselves, complete inputs
-for our 'hello' 'Parser'. This is fine; we want to be able to feed the
-'Parser' with either partial or complete input as soon as it's
-received from upstream. More input will be requested when needed.
-Attoparsec's 'Parser' handles partial parsing just fine.
-
-  >>> runProxy $  fromListS input1 >-> helloPipe1 >-> printD
-  Name "Kate"
-  Name "Mary"
-  Name "Jeff"
-  Name "Tom"
-
-We have accomplished our simple goal: We've made a 'Pipe' that parses
-downstream flowing input using our 'Parser' 'hello'.
-
-
-$example-errors
-
-Let's try with some more complex input.
-
-  > input2 :: [Text]
-  > input2 =
-  >   [ "Hello Amy."
-  >   , "Hello, Hello Tim."
-  >   , "Hello Bob."
-  >   , "Hello James"
-  >   , "Hello"
-  >   , "Hello World."
-  >   , "HexHello Jon."
-  >   , "H"
-  >   , "ello Ann"
-  >   , "."
-  >   , "Hello Jean-Luc."
-  >   ]
-
-  >>> runProxy $ fromListS input2 >-> helloPipe1 >-> printD
-  Name "Amy"
-  Name "Bob"
-  Name "JamesHelloHello World"
-  Name "Ann"
-  Name "Jean-Luc"
-
-The simple @helloPipe1@ we built skips /chunks/ of input that fail to be
-parsed, and then continues parsing new input. That approach might be
-enough if you are certain your input is always well-formed, but
-sometimes you may prefer to act differently on these extraordinary
-situations.
-
-Instead of just using 'parserInputD' and 'parserD' to build our
-'helloPipe1', we could have used an additional 'Proxy' in between them to
-handle these situations. The module "Control.Proxy.Attoparsec.Control"
-exports some useful 'Proxy's that serve this purpose. The default
-behavior just mentioned resembles the one provided by
-'skipMalformedChunks'.
-
-Here are some other examples:
-
-['retryLeftovers']
-   On parsing failures, keep retrying with any left-over input, skipping
-   individual bits each time. If there are no left-overs, then more
-   input is requests form upstream.
-
-  > helloPipe2 :: (Proxy p, Monad m) => () -> Pipe p Text Name m r
-  > helloPipe2 = parserInputD >-> retryLeftovers >-> parserD hello
-
-  >>> runProxy $ fromListS input2 >-> helloPipe2 >-> printD
-  Name "Amy"
-  Name "Tim"
-  Name "Bob"
-  Name "JamesHelloHello World"
-  Name "Jon"
-  Name "Ann"
-  Name "Jean-Luc"
-
-['throwParsingErrors']
-  When a parsing error arises, aborts execution by throwing
-  'MalformedInput' in the 'EitherP' proxy transformer.
-
-  > helloPipe3 :: (Proxy p, Monad m) => () -> Pipe (EitherP BadInput p) Text Name m r
-  > helloPipe3 = parserInputD >-> throwParsingErrors >-> parserD hello
-
-  >>> runProxy . runEitherK $ fromListS input2 >-> helloPipe3 >-> printD
-  Name "Amy"
-  Left (MalformedInput {miParserErrror = ParserError {errorContexts = [], errorMessage = "Failed reading: takeWith"}})
-
-[@'limitInputLength' n@]
-  If a @'Parser' a b@ has consumed input @a@ of length longer than
-  @n@ without producing a @b@ value, and it's still requesting more
-  input, then throw 'InputTooLong' in the 'EitherP' proxy transformer.
-
-  > helloPipe4 :: (Proxy p, Monad m) => () -> Pipe (EitherP BadInput p) Text Name m r
-  > helloPipe4 = parserInputD >-> limitInputLength 10 >-> parserD hello
-
-  >>> runProxy . runEitherK $ fromListS input2 >-> helloPipe4 >-> printD
-  Name "Amy"
-  Name "Bob"
-  Left (InputTooLong {itlLenght = 11})
-
-  Notice that by default, as mentioned earlier, parsing errors are
-  ignored by skipping the malformed /chunk/. That's why we didn't get any
-  complaint about the malformed input between /“Amy”/ and /“Bob”/.
-
-
-$example-compose-control
-
-These 'Proxy's that control the parsing behavior can be easily plugged
-together with @('>->')@ to achieve a combined functionality. Keep in
-mind that the order in which these 'Proxy's are used is important.
-
-Suppose you don't want to parse inputs of length longer than 10, and on
-parsing failures, you want to retry feeding the parser with any
-left-overs. You could achieve that behaviour like this:
-
-  > helloPipe5 :: (Proxy p, Monad m) => () -> Pipe (EitherP BadInput p) Text Name m r
-  > helloPipe5 = parserInputD >-> limitInputLength 10 >-> retryLeftovers >-> parserD hello
-
-  >>> runProxy . runEitherK $ fromListS input2 >-> helloPipe5 >-> printD
-  Name "Amy"
-  Name "Tim"
-  Name "Bob"
-  Left (InputTooLong {itlLenght = 11})
-
-
-$example-control-custom
-
-In case the 'Proxy's provided by "Control.Proxy.Attoparsec.Control" are not
-enough for your needs, you can create your custom parsing control 'Proxy'.
-
-Through a parsing control 'Proxy',  @'ParserStatus' a@ values flow
-upstream and @'ParserSupply' a@ values flow downstream.  A parsing
-control 'Proxy' may use, replace, or alter the flow of these values to
-achieve its purpose. A @'ParserStatus' a@ value received from downstream
-reports the status of a 'parserD' parsing 'Proxy', and in exchange,
-downstream expects a @'ParserSupply' a@ value.
-
-@'ParserSupply' a@ values carry raw input to be parsed and directives on how it
-should be used. @'ParserSupply' a@ is just a type synonym for
-@('SupplyUse', a)@. The @a@ value is the input chunk, and the 'SupplyUse' value
-could be either 'Resume' if the parser currently waiting for input should be
-fed, or 'Start', if a new parser should be started and fed the input,
-effectively aborting any parsing activity currently waiting for more input.
-
-See the documentation about 'ParserStatus' and 'ParserSupply' for more details.
-
-Suppose you want to write a parsing control 'Proxy' that never provides
-additional input to partial parsing results. Let's first take a look at the
-type of this 'Proxy':
-
-  > skipPartialResults
-  >  :: (Monad m, Proxy p, AttoparsecInput a)
-  >  => ParserStatus a
-  >  -> p (ParserStatus a) (ParserSupply a) (ParserStatus a) (ParserSupply a) m r
-
-Just like we said, @'ParserStatus' a@ values flow upstream and @'ParserSupply'
-a@ values flow downstream.
-
-Now to a simple implementation: If we receive @'Parsing' n@ from downstream,
-then we know there is a partial parsing result waiting for more input. If we
-were to respond to this request with @('Resume', a)@, then the partial parser
-would continue consuming input, but if we change our response to @('Start', a)@,
-then the partial parser would be aborted and a new parser would start
-consuming the given input. A simple implementation is quite straightforward:
-
-  > skipPartialResults = runIdentityK . foreverK $ go
-  >   where go x@(Parsing _) = request x >>= \(_, a) -> respond (Start, a)
-  >         go x             = request x >>= respond
-
-We forward upstream the requests we get from downstream. However, in the case
-of a @'Parsing' n@ status, we replace with 'Start' the first value in the
-@'ParserSupply' a@ pair we receive from upstream before responding.
-
-Now we can use this parsing control 'Proxy' with some simple input and see it
-working.
-
-  > helloPipe6 :: (Proxy p, Monad m) => () -> Pipe p Text Name m r
-  > helloPipe6 = parserInputD >-> skipPartialResults >-> parserD hello
-
-  >>> runProxy $ fromListS input1 >-> helloPipe6 >-> printD
-  Name "Kate"
-  Name "Mary"
-
-
-$example-try
-
-This module exports the following previous examples so that you can try
-them.
-
diff --git a/src/Control/Proxy/Attoparsec/Types.hs b/src/Control/Proxy/Attoparsec/Types.hs
deleted file mode 100644
--- a/src/Control/Proxy/Attoparsec/Types.hs
+++ /dev/null
@@ -1,101 +0,0 @@
-{-# LANGUAGE DeriveFunctor  #-}
-{-# LANGUAGE KindSignatures #-}
-
--- | This module exports common types used throughout
--- @"Control.Proxy.Attoparsec".*@
-
-module Control.Proxy.Attoparsec.Types
-  ( -- * Proxy control
-    ParserStatus(..)
-  , SupplyUse(..)
-  , ParserSupply
-    -- * Error types
-  , BadInput(..)
-    -- * Attoparsec integration
-  , AttoparsecInput(..)
-  , ParserError(..)
-  ) where
-
-import qualified Data.Attoparsec.ByteString as ABS
-import qualified Data.Attoparsec.Text       as AT
-import           Data.Attoparsec.Types
-import qualified Data.ByteString            as BS
-import qualified Data.Text                  as T
-
-
-
--- | Status of a parsing 'Proxy'.
-data ParserStatus a
-  -- | There is a 'Parser' running and waiting for more @a@ input.
-  --
-  -- Receiving @('Resume', a)@ from upstream would feed input @a@ to the 'Parser'
-  -- waiting for more input.
-  = Parsing
-    { psLength :: Int -- ^Length of input consumed so far.
-    }
-  -- | A 'Parser' has failed parsing.
-  --
-  -- Receiving @('Resume', a)@ from upstream would feed input @a@ to a newly
-  -- started 'Parser'.
-  | Failed
-    { psLeftover :: a -- ^Input not yet consumed when the failure occurred.
-    , psError    :: ParserError -- ^Error found while parsing.
-    }
-  deriving (Show, Eq)
-
-
-data ParserError = ParserError
-    { errorContexts :: [String]  -- ^ Contexts where the error occurred.
-    , errorMessage  :: String    -- ^ Error message.
-    } deriving (Show, Eq)
-
-
--- | Indicates how should a parsing 'Proxy' use new input.
-data SupplyUse
-  -- | Start a new parser and fed any new input to it.
-  = Start
-  -- | Resume feeding any new input to the current parser waiting for input.
-  | Resume
-  deriving (Eq, Show)
-
-
--- | Input supplied to a parsing 'Proxy'.
---
--- The 'SupplyUse' value indicates how the @a@ input chunk should be used.
-type ParserSupply a = (SupplyUse, a)
-
-
--- | Reasons for an input value to be unnaceptable.
-data BadInput
-  = InputTooLong
-    { itlLength :: Int -- ^ Length of the input.
-    }
-  | MalformedInput
-    { miParserErrror :: ParserError -- ^ Error found while parsing.
-    }
-  deriving (Show, Eq)
-
-
--- | A class for valid Attoparsec input types.
-class Eq a => AttoparsecInput a where
-    -- | Run a 'Parser' with input @a@.
-    parse :: Parser a b -> a -> IResult a b
-    -- | Tests whether @a@ is empty.
-    null :: a -> Bool
-    -- | Skips the first @n@ elements from @a@ and returns the rest.
-    drop :: Int -> a -> a
-    -- | Number of elements in @a@.
-    length :: a -> Int
-
-instance AttoparsecInput BS.ByteString where
-    parse = ABS.parse
-    null = BS.null
-    drop = BS.drop
-    length = BS.length
-
-instance AttoparsecInput T.Text where
-    parse = AT.parse
-    null = T.null
-    drop = T.drop
-    length = T.length
-
diff --git a/tests/Main.hs b/tests/Main.hs
--- a/tests/Main.hs
+++ b/tests/Main.hs
@@ -1,19 +1,17 @@
-module Main where
+module Main (main) where
 
 import Test.Framework (defaultMain, testGroup)
 import Test.Framework.Providers.QuickCheck2 (testProperty)
 import Test.Framework.Providers.HUnit (testCase)
 import Test.HUnit
 
-import qualified Test.Tutorial
 import qualified Test.Attoparsec
 
 main = defaultMain tests
 
 tests =
-    [ testGroup "Sample"   sampleTests
-    , testGroup "Tutorial" Test.Tutorial.tests
-    , testGroup "Attoparsec" Test.Attoparsec.tests
+    [ testGroup "Sample."   sampleTests
+    , testGroup "Attoparsec." Test.Attoparsec.tests
     ]
 
 sampleTests = [ testProperty "QuickCheck" $ \x -> const True (x :: Int) == True
diff --git a/tests/Test/Attoparsec.hs b/tests/Test/Attoparsec.hs
--- a/tests/Test/Attoparsec.hs
+++ b/tests/Test/Attoparsec.hs
@@ -1,7 +1,67 @@
 {-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE NoMonomorphismRestriction #-}
 
 module Test.Attoparsec (tests) where
 
--- TODO
+import           Control.Monad
+import           Control.Proxy                  ((>->))
+import qualified Control.Proxy                  as P
+import qualified Control.Proxy.Trans.State      as P
+import qualified Control.Proxy.Trans.Either     as P
+import qualified Control.Proxy.Trans.Writer     as P
+import qualified Control.Proxy.Parse            as Pa
+import           Control.Proxy.Attoparsec       (parseD)
+import qualified Data.Attoparsec.Text           as AT
+import qualified Data.Text                      as T
+import           Data.Maybe
+import           Test.Framework.Providers.HUnit (testCase)
+import           Test.HUnit                     (Assertion, assert)
 
-tests = []
+-- | Parses a 'Char' repeated four times.
+four :: AT.Parser Char
+four = do
+   c <- AT.anyChar
+   replicateM_ 3 $ AT.char c
+   return c
+
+type ParseTest = (Bool, String, [T.Text], [Char], [T.Text])
+
+
+assertFoursTest :: ParseTest -> Assertion
+assertFoursTest (ok, _title, input, output, mlo) = assert . fromJust $ do
+  let srcS = (Pa.wrap.) $ P.fromListS input
+      run = P.runProxy . P.runWriterK . P.runStateK Pa.mempty . P.runEitherK
+  ((epe,mlo'), res) <- run $ srcS >-> parseD four
+                                  >-> P.liftP . P.liftP . P.toListD
+  let okMlo = mlo' == mlo
+      okErr = either (const $ not ok) (const $ ok) epe
+      okRes = res == output
+  return $ okMlo && okErr && okRes
+
+foursTests :: [ParseTest]
+foursTests =
+  [ (True  ,"0 chunk"                   ,[]                 ,[]        ,[])
+  , (True  ,"1 chunk: Empty"            ,[]                 ,[]        ,[])
+  , (True  ,"1 chunk: One"              ,["aaaa"]           ,['a']     ,[])
+  , (True  ,"1 chunk: One twice"        ,["aaaaaaaa"]       ,['a','a'] ,[])
+  , (True  ,"1 chunk: Two"              ,["aaaabbbb"]       ,['a','b'] ,[])
+  , (True  ,"1 chunk: Two between null" ,["aaaa","","bbbb"] ,['a','b'] ,[])
+  , (False ,"1 chunk: Partial"          ,["aaaab"]          ,['a']     ,[])
+  , (False ,"1 chunk: Wrong"            ,["aaxbb"]          ,[]        ,["xbb"])
+  , (False ,"1 chunk: One then wrong"   ,["aaaavz"]         ,['a']     ,["z"])
+  , (True  ,"2 chunk: Empty"            ,["",""]            ,[]        ,[])
+  , (True  ,"2 chunk: Empty then one"   ,["","aaaa"]        ,['a']     ,[])
+  , (True  ,"2 chunk: One"              ,["a","aaa"]        ,['a']     ,[])
+  , (True  ,"2 chunk: One'"             ,["aa","aa"]        ,['a']     ,[])
+  , (True  ,"2 chunk: One''"            ,["aaa","a"]        ,['a']     ,[])
+  , (True  ,"2 chunk: One'''"           ,["aaaa",""]        ,['a']     ,[])
+  , (True  ,"2 chunk: Two"              ,["aaaa","bbbb"]    ,['a','b'] ,[])
+  , (False ,"2 chunk: Wrong"            ,["abcd","efgh"]    ,[]        ,["bcd"])
+  , (False ,"2 chunk: One then wrong"   ,["aaaab","bxz"]    ,['a']     ,["xz"])
+  , (True  ,"3 chunk: One"              ,["a","a","aa"]     ,['a']     ,[])
+  ]
+
+testCaseFoursTest ft@(_,name,_,_,_) =
+  testCase ("Fours." ++ name) $ assertFoursTest ft
+
+tests = map testCaseFoursTest foursTests
diff --git a/tests/Test/Tutorial.hs b/tests/Test/Tutorial.hs
deleted file mode 100644
--- a/tests/Test/Tutorial.hs
+++ /dev/null
@@ -1,66 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
-
-module Test.Tutorial where
-
-import           Control.Proxy
-import           Control.Proxy.Attoparsec
-import           Control.Proxy.Attoparsec.Tutorial
-import           Control.Proxy.Trans.Either
-import           Data.Maybe
-import           Test.Framework.Providers.HUnit    (testCase)
-import           Test.HUnit                        hiding (test)
-
-
-testPipe pipe input test = fromJust $ do
-  let proxy = fromListS input >-> pipe >-> toListD
-  output <- runWriterT . runProxy . runEitherK $ proxy
-  return . assert $ test output
-
-
-test_helloPipe1_input1 = testPipe helloPipe1 input1 test
-  where test (Right _, x) = x == fmap Name ["Kate" , "Mary", "Jeff", "Tom"]
-        test _            = False
-
-test_helloPipe1_input2 = testPipe helloPipe1 input2 test
-  where test (Right _, x) = x == fmap Name [ "Amy", "Bob"
-                                           , "JamesHelloHello World" , "Ann"
-                                           , "Jean-Luc" ]
-        test _            = False
-
-
-test_helloPipe2_input2 = testPipe helloPipe2 input2 test
-   where test (Right _, x) = x == fmap Name [ "Amy" ,"Tim", "Bob"
-                                            , "JamesHelloHello World", "Jon"
-                                            , "Ann" , "Jean-Luc" ]
-         test _            = False
-
-test_helloPipe3_input2 = testPipe helloPipe3 input2 test
-   where test (Left (MalformedInput _), [Name "Amy"]) = True
-         test _                                       = False
-
-
-test_helloPipe4_input2 = testPipe helloPipe4 input2 test
-   where test (Left (InputTooLong 11), [Name "Amy", Name "Bob"]) = True
-         test _                                                  = False
-
-
-test_helloPipe5_input2 = testPipe helloPipe5 input2 test
-   where test (Left (InputTooLong 11),
-               [Name "Amy", Name "Tim", Name "Bob"]) = True
-         test _                                      = False
-
-test_helloPipe6_input1 = testPipe helloPipe6 input1 test
-   where test (Right _, [Name "Kate", Name "Mary"]) = True
-         test _                                     = False
-
-
-tests =
-    [ testCase "helloPipe1 + input1" test_helloPipe1_input1
-    , testCase "helloPipe1 + input2" test_helloPipe1_input2
-    , testCase "helloPipe2 + input2" test_helloPipe2_input2
-    , testCase "helloPipe3 + input2" test_helloPipe3_input2
-    , testCase "helloPipe4 + input2" test_helloPipe4_input2
-    , testCase "helloPipe5 + input2" test_helloPipe5_input2
-    , testCase "helloPipe6 + input1" test_helloPipe6_input1
-    ]
-
