diff --git a/CHANGELOG b/CHANGELOG
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,8 @@
+1.0.2.2
+
+* Added some good documentation. Courtesy of Franz Thoma.
+
+
 1.0.2.1
 
 * Refer to Michael Snoyman's excellent tutorial on monad-control.
diff --git a/Control/Monad/Trans/Control.hs b/Control/Monad/Trans/Control.hs
--- a/Control/Monad/Trans/Control.hs
+++ b/Control/Monad/Trans/Control.hs
@@ -35,6 +35,33 @@
 See the following tutorial by Michael Snoyman on how to use this package:
 
 <https://www.yesodweb.com/book/monad-control>
+
+=== Quick implementation guide
+
+Given a base monad @B@ and a stack of transformers @T@:
+
+* Define instances @'MonadTransControl' T@ for all transformers @T@, using the
+  @'defaultLiftWith'@ and @'defaultRestoreT'@ functions on the constructor and
+  deconstructor of @T@.
+
+* Define an instance @'MonadBaseControl' B B@ for the base monad:
+
+    @
+    instance MonadBaseControl B B where
+        type StM B a   = a
+        liftBaseWith f = f 'id'
+        restoreM       = 'return'
+    @
+
+* Define instances @'MonadBaseControl' B m => 'MonadBaseControl' B (T m)@ for
+  all transformers:
+
+    @
+    instance MonadBaseControl b m => MonadBaseControl b (T m) where
+        type StM (T m) a = 'ComposeSt' T m a
+        liftBaseWith f   = 'defaultLiftBaseWith'
+        restoreM         = 'defaultRestoreM'
+    @
 -}
 
 module Control.Monad.Trans.Control
@@ -44,6 +71,7 @@
       -- ** Defaults
       -- $MonadTransControlDefaults
     , RunDefault, defaultLiftWith, defaultRestoreT
+      -- *** Defaults for a stack of two
       -- $MonadTransControlDefaults2
     , RunDefault2, defaultLiftWith2, defaultRestoreT2
 
@@ -121,13 +149,59 @@
 -- MonadTransControl type class
 --------------------------------------------------------------------------------
 
+-- | The @MonadTransControl@ type class is a stronger version of @'MonadTrans'@:
+--
+-- Instances of @'MonadTrans'@ know how to @'lift'@ actions in the base monad to
+-- the transformed monad. These lifted actions, however, are completely unaware
+-- of the monadic state added by the transformer.
+--
+-- @'MonadTransControl'@ instances are aware of the monadic state of the
+-- transformer and allow to save and restore this state.
+--
+-- This allows to lift functions that have a monad transformer in both positive
+-- and negative position. Take, for example, the function
+--
+-- @
+-- withFile :: FilePath -> IOMode -> (Handle -> IO r) -> IO r
+-- @
+--
+-- @'MonadTrans'@ instances can only lift the return type of the @withFile@
+-- function:
+--
+-- @
+-- withFileLifted :: MonadTrans t => FilePath -> IOMode -> (Handle -> IO r) -> t IO r
+-- withFileLifted file mode action = lift (withFile file mode action)
+-- @
+--
+-- However, @'MonadTrans'@ is not powerful enough to make @withFileLifted@
+-- accept a function that returns @t IO@. The reason is that we need to take
+-- away the transformer layer in order to pass the function to @'withFile'@.
+-- @'MonadTransControl'@ allows us to do this:
+--
+-- @
+-- withFileLifted' :: (Monad (t IO), MonadTransControl t) => FilePath -> IOMode -> (Handle -> t IO r) -> t IO r
+-- withFileLifted' file mode action = liftWith (\\run -> withFile file mode (run . action)) >>= restoreT . return
+-- @
 class MonadTrans t => MonadTransControl t where
   -- | Monadic state of @t@.
   --
-  -- For clarity, because haddock does not display associated types, below are
-  -- the elaborated 'StT' definitions provided by this library:
+  -- The monadic state of a monad transformer is the result type of its @run@
+  -- function, e.g.:
   --
   -- @
+  -- 'runReaderT' :: 'ReaderT' r m a -> r -> m a
+  -- 'StT' ('ReaderT' r) a ~ a
+  --
+  -- 'runStateT' :: 'StateT' s m a -> s -> m (a, s)
+  -- 'StT' ('StateT' s) a ~ (a, s)
+  --
+  -- 'runMaybeT' :: 'MaybeT' m a -> m ('Maybe' a)
+  -- 'StT' 'MaybeT' a ~ 'Maybe' a
+  -- @
+  --
+  -- Provided type instances:
+  --
+  -- @
   -- StT 'IdentityT'    a ~ a
   -- StT 'MaybeT'       a ~ 'Maybe' a
   -- StT ('ErrorT' e)   a ~ 'Error' e => 'Either' e a
@@ -152,7 +226,29 @@
   -- The difference with 'lift' is that before lifting the @m@ computation
   -- @liftWith@ captures the state of @t@. It then provides the @m@
   -- computation with a 'Run' function that allows running @t n@ computations in
-  -- @n@ (for all @n@) on the captured state.
+  -- @n@ (for all @n@) on the captured state, e.g.
+  --
+  -- @
+  -- withFileLifted :: (Monad (t IO), MonadTransControl t) => FilePath -> IOMode -> (Handle -> t IO r) -> t IO r
+  -- withFileLifted file mode action = liftWith (\\run -> withFile file mode (run . action)) >>= restoreT . return
+  -- @
+  --
+  -- If the @Run@ function is ignored, @liftWith@ coincides with @lift@:
+  --
+  -- @lift f = liftWith (const f)@
+  --
+  -- Implementations use the @'Run'@ function associated with a transformer:
+  --
+  -- @
+  -- liftWith :: 'Monad' m => (('Monad' n => 'ReaderT' r n b -> n b) -> m a) -> 'ReaderT' r m a
+  -- liftWith f = 'ReaderT' (\r -> f (\action -> 'runReaderT' action r))
+  --
+  -- liftWith :: 'Monad' m => (('Monad' n => 'StateT' s n b -> n (b, s)) -> m a) -> 'StateT' s m a
+  -- liftWith f = 'StateT' (\s -> 'liftM' (\x -> (x, s)) (f (\action -> 'runStateT' action s)))
+  --
+  -- liftWith :: 'Monad' m => (('Monad' n => 'MaybeT' n b -> n ('Maybe' b)) -> m a) -> 'MaybeT' m a
+  -- liftWith f = 'MaybeT' ('liftM' 'Just' (f 'runMaybeT'))
+  -- @
   liftWith :: Monad m => (Run t -> m a) -> t m a
 
   -- | Construct a @t@ computation from the monadic state of @t@ that is
@@ -162,6 +258,23 @@
   --
   -- @liftWith (\\run -> run t) >>= restoreT . return = t@
   --
+  -- @restoreT@ is usually implemented through the constructor of the monad
+  -- transformer:
+  --
+  -- @
+  -- 'ReaderT'  :: (r -> m a) -> 'ReaderT' r m a
+  -- restoreT ::       m a  -> 'ReaderT' r m a
+  -- restoreT action = 'ReaderT' { runReaderT = 'const' action }
+  --
+  -- 'StateT'   :: (s -> m (a, s)) -> 'StateT' s m a
+  -- restoreT ::       m (a, s)  -> 'StateT' s m a
+  -- restoreT action = 'StateT' { runStateT = 'const' action }
+  --
+  -- 'MaybeT'   :: m ('Maybe' a) -> 'MaybeT' m a
+  -- restoreT :: m ('Maybe' a) -> 'MaybeT' m a
+  -- restoreT action = 'MaybeT' action
+  -- @
+  --
   -- Example type signatures:
   --
   -- @
@@ -197,6 +310,14 @@
 -- Run ('WriterT' w)  ~ forall n b. ('Monad' n, 'Monoid' w) => 'WriterT' w  n b -> n (a, w)
 -- Run ('RWST' r w s) ~ forall n b. ('Monad' n, 'Monoid' w) => 'RWST' r w s n b -> n (a, s, w)
 -- @
+--
+-- This type is usually satisfied by the @run@ function of a transformer:
+--
+-- @
+-- 'flip' 'runReaderT' :: r -> Run ('ReaderT' r)
+-- 'flip' 'runStateT'  :: s -> Run ('StateT' s)
+-- 'runMaybeT'       ::      Run 'MaybeT'
+-- @
 type Run t = forall n b. Monad n => t n b -> n (StT t b)
 
 
@@ -207,8 +328,8 @@
 -- $MonadTransControlDefaults
 --
 -- The following functions can be used to define a 'MonadTransControl' instance
--- for a monad transformer which simply wraps another monad transformer which
--- already has a @MonadTransControl@ instance. For example:
+-- for a monad transformer which simply is a newtype around another monad
+-- transformer which already has a @MonadTransControl@ instance. For example:
 --
 -- @
 -- {-\# LANGUAGE GeneralizedNewtypeDeriving \#-}
@@ -389,10 +510,18 @@
 -- MonadBaseControl type class
 --------------------------------------------------------------------------------
 
+-- |
+-- == Writing instances
+--
+-- The usual way to write a @'MonadBaseControl'@ instance for a transformer
+-- stack over a base monad @B@ is to write an instance @MonadBaseControl B B@
+-- for the base monad, and @MonadTransControl T@ instances for every transformer
+-- @T@. Instances for @'MonadBaseControl'@ are then simply implemented using
+-- @'ComposeSt'@, @'defaultLiftBaseWith'@, @'defaultRestoreM'@.
 class MonadBase b m => MonadBaseControl b m | m -> b where
-    -- | Monadic state of @m@.
+    -- | Monadic state that @m@ adds to the base monad @b@.
     --
-    -- For all non-transformer monads, @StM m a ~ a@:
+    -- For all base (non-transformed) monads, @StM m a ~ a@:
     --
     -- @
     -- StM 'IO'         a ~ a
@@ -405,20 +534,20 @@
     -- StM ('ST' s)     a ~ a
     -- @
     --
-    -- All transformer monads\' 'StM' depends on both the monadic state of the
-    -- transformer (given by its 'StT' from 'MonadTransControl'), as well as its
-    -- inner monad's monadic state, given by its 'StM' from 'MonadBaseControl':
+    -- If @m@ is a transformed monad, @m ~ t b@, @'StM'@ is the monadic state of
+    -- the transformer @t@ (given by its 'StT' from 'MonadTransControl'). For a
+    -- transformer stack, @'StM'@ is defined recursively:
     --
     -- @
-    -- StM ('IdentityT'  m) a ~ StM m a
-    -- StM ('MaybeT'     m) a ~ StM m ('Maybe' a)
-    -- StM ('ErrorT' e   m) a ~ 'Error' e => StM m ('Either' e a)
-    -- StM ('ExceptT' e  m) a ~ StM m ('Either' e a)
-    -- StM ('ListT'      m) a ~ StM m [a]
-    -- StM ('ReaderT' r  m) a ~ StM m a
-    -- StM ('StateT' s   m) a ~ StM m (a, s)
-    -- StM ('WriterT' w  m) a ~ 'Monoid' w => StM m (a, w)
-    -- StM ('RWST' r w s m) a ~ 'Monoid' w => StM m (a, s, w)
+    -- StM ('IdentityT'  m) a ~ 'ComposeSt' 'IdentityT' m a ~ StM m a
+    -- StM ('MaybeT'     m) a ~ 'ComposeSt' 'MaybeT'    m a ~ StM m ('Maybe' a)
+    -- StM ('ErrorT' e   m) a ~ 'ComposeSt' 'ErrorT'    m a ~ 'Error' e => StM m ('Either' e a)
+    -- StM ('ExceptT' e  m) a ~ 'ComposeSt' 'ExceptT'   m a ~ StM m ('Either' e a)
+    -- StM ('ListT'      m) a ~ 'ComposeSt' 'ListT'     m a ~ StM m [a]
+    -- StM ('ReaderT' r  m) a ~ 'ComposeSt' 'ReaderT'   m a ~ StM m a
+    -- StM ('StateT' s   m) a ~ 'ComposeSt' 'StateT'    m a ~ StM m (a, s)
+    -- StM ('WriterT' w  m) a ~ 'ComposeSt' 'WriterT'   m a ~ 'Monoid' w => StM m (a, w)
+    -- StM ('RWST' r w s m) a ~ 'ComposeSt' 'RWST'      m a ~ 'Monoid' w => StM m (a, s, w)
     -- @
     type StM m a :: *
 
@@ -434,7 +563,17 @@
     -- The difference with 'liftBase' is that before lifting the base computation
     -- @liftBaseWith@ captures the state of @m@. It then provides the base
     -- computation with a 'RunInBase' function that allows running @m@
-    -- computations in the base monad on the captured state.
+    -- computations in the base monad on the captured state:
+    --
+    -- @
+    -- withFileLifted :: MonadBaseControl IO m => FilePath -> IOMode -> (Handle -> m a) -> m a
+    -- withFileLifted file mode action = liftBaseWith (\\runInBase -> withFile file mode (runInBase . action)) >>= restoreM
+    --                              -- = control $ \\runInBase -> withFile file mode (runInBase . action)
+    --                              -- = liftBaseOp (withFile file mode) action
+    -- @
+    --
+    -- @'liftBaseWith'@ is usually not implemented directly, but using
+    -- @'defaultLiftBaseWith'@.
     liftBaseWith :: (RunInBase m b -> b a) -> m a
 
     -- | Construct a @m@ computation from the monadic state of @m@ that is
@@ -443,6 +582,9 @@
     -- Instances should satisfy:
     --
     -- @liftBaseWith (\\runInBase -> runInBase m) >>= restoreM = m@
+    --
+    -- @'restoreM'@ is usually not implemented directly, but using
+    -- @'defaultRestoreM'@.
     restoreM :: StM m a -> m a
 
 -- | A function that runs a @m@ computation on the monadic state that was
@@ -465,6 +607,8 @@
 -- RunInBase ('WriterT' w  m) b ~ forall a. 'Monoid' w => 'WriterT' w  m a -> b ('StM' m (a, w))
 -- RunInBase ('RWST' r w s m) b ~ forall a. 'Monoid' w => 'RWST' r w s m a -> b ('StM' m (a, s, w))
 -- @
+--
+-- For a transformed base monad @m ~ t b@, @'RunInBase m b' ~ 'Run' t@.
 type RunInBase m b = forall a. m a -> b (StM m a)
 
 
@@ -593,6 +737,16 @@
 --------------------------------------------------------------------------------
 
 -- | An often used composition: @control f = 'liftBaseWith' f >>= 'restoreM'@
+--
+-- Example:
+--
+-- @
+-- liftedBracket :: MonadBaseControl IO m => m a -> (a -> m b) -> (a -> m c) -> m c
+-- liftedBracket acquire release action = control $ \\runInBase ->
+--     bracket (runInBase acquire)
+--             (\\saved -> runInBase (restoreM saved >>= release))
+--             (\\saved -> runInBase (restoreM saved >>= action))
+-- @
 control :: MonadBaseControl b m => (RunInBase m b -> b (StM m a)) -> m a
 control f = liftBaseWith f >>= restoreM
 {-# INLINABLE control #-}
@@ -622,11 +776,15 @@
 -- | @liftBaseOp@ is a particular application of 'liftBaseWith' that allows
 -- lifting control operations of type:
 --
--- @((a -> b c) -> b c)@ to: @('MonadBaseControl' b m => (a -> m c) -> m c)@.
+-- @((a -> b c) -> b c)@
 --
+-- to:
+--
+-- @('MonadBaseControl' b m => (a -> m c) -> m c)@
+--
 -- For example:
 --
--- @liftBaseOp alloca :: 'MonadBaseControl' 'IO' m => (Ptr a -> m c) -> m c@
+-- @liftBaseOp alloca :: (Storable a, 'MonadBaseControl' 'IO' m) => (Ptr a -> m c) -> m c@
 liftBaseOp :: MonadBaseControl b m
            => ((a -> b (StM m c)) -> b (StM m d))
            -> ((a ->        m c)  ->        m d)
@@ -636,8 +794,12 @@
 -- | @liftBaseOp_@ is a particular application of 'liftBaseWith' that allows
 -- lifting control operations of type:
 --
--- @(b a -> b a)@ to: @('MonadBaseControl' b m => m a -> m a)@.
+-- @(b a -> b a)@
 --
+-- to:
+--
+-- @('MonadBaseControl' b m => m a -> m a)@
+--
 -- For example:
 --
 -- @liftBaseOp_ mask_ :: 'MonadBaseControl' 'IO' m => m a -> m a@
@@ -650,8 +812,12 @@
 -- | @liftBaseDiscard@ is a particular application of 'liftBaseWith' that allows
 -- lifting control operations of type:
 --
--- @(b () -> b a)@ to: @('MonadBaseControl' b m => m () -> m a)@.
+-- @(b () -> b a)@
 --
+-- to:
+--
+-- @('MonadBaseControl' b m => m () -> m a)@
+--
 -- Note that, while the argument computation @m ()@ has access to the captured
 -- state, all its side-effects in @m@ are discarded. It is run only for its
 -- side-effects in the base monad @b@.
@@ -666,7 +832,11 @@
 -- | @liftBaseOpDiscard@ is a particular application of 'liftBaseWith' that allows
 -- lifting control operations of type:
 --
--- @((a -> b ()) -> b c)@ to: @('MonadBaseControl' b m => (a -> m ()) -> m c)@.
+-- @((a -> b ()) -> b c)@
+--
+-- to:
+--
+-- @('MonadBaseControl' b m => (a -> m ()) -> m c)@
 --
 -- Note that, while the argument computation @m ()@ has access to the captured
 -- state, all its side-effects in @m@ are discarded. It is run only for its
diff --git a/README.markdown b/README.markdown
--- a/README.markdown
+++ b/README.markdown
@@ -12,9 +12,6 @@
 operators and exploits the `RankNTypes` language extension to simplify
 most definitions.
 
-The package includes a copy of the `monad-peel` testsuite written by
-Anders Kaseorg The tests can be performed by using `cabal test`.
-
 [This `criterion`](https://github.com/basvandijk/bench-monad-peel-control)
 based benchmark shows that `monad-control` is on average about 2.5
 times faster than `monad-peel`.
diff --git a/monad-control.cabal b/monad-control.cabal
--- a/monad-control.cabal
+++ b/monad-control.cabal
@@ -1,5 +1,5 @@
 Name:                monad-control
-Version:             1.0.2.1
+Version:             1.0.2.2
 Synopsis:            Lift control operations, like exception catching, through monad transformers
 License:             BSD3
 License-file:        LICENSE
