diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,7 +1,13 @@
 # Revision history for deriving-trans
 
+## 0.2.2.0 *30 Jan 2022*
+
+* Add "base-case" instances for mtl's type classes to `ComposeT`.
+* Add Haddock examples and improve comments.
+
 ## 0.2.1.0 *27 Jan 2022*
 
+* Add `MonadTrans` and `MonadTransControl` instances to `Elevator`.
 * Use StandaloneKindSignatures.
 * Add Haddock documentation.
 
diff --git a/deriving-trans.cabal b/deriving-trans.cabal
--- a/deriving-trans.cabal
+++ b/deriving-trans.cabal
@@ -1,9 +1,10 @@
 cabal-version:       3.0
 name:                deriving-trans
-version:             0.2.1.0
+version:             0.2.2.0
 synopsis:            Derive instances for monad transformer stacks
 description:         Implementing instances for monad transformer stacks can be tedious.
-                     <https://hackage.haskell.org/package/mtl mtl> defines each instance for each transfomer.
+                     <https://hackage.haskell.org/package/mtl mtl> defines each instance for each
+                     transfomer, but this can be avoided.
 
                      'Elevator' let's you access instances of the underlying monad of a transformer.
                      Composing transformers with 'ComposeT' brings instances into scope during the
@@ -11,7 +12,8 @@
 
                      'Elevator' can be used with DerivingVia to select a specific transformer to
                      derive instances for a transformer stack.
-                     'ComposeT' composes transformers and accumulates instances in a transformer stack.
+                     'ComposeT' composes transformers and accumulates instances in a transformer
+                     stack.
 license:             BSD-3-Clause
 license-file:        LICENSE
 author:              Felix Springer
diff --git a/src/Control/Monad/Trans/Compose.hs b/src/Control/Monad/Trans/Compose.hs
--- a/src/Control/Monad/Trans/Compose.hs
+++ b/src/Control/Monad/Trans/Compose.hs
@@ -3,20 +3,33 @@
 module Control.Monad.Trans.Compose where
 
 import Control.Monad.Base
-import Control.Monad.Error.Class
-import Control.Monad.IO.Class
-import Control.Monad.Reader.Class
-import Control.Monad.State.Class
-import Control.Monad.Trans
+import Control.Monad.Except
+import Control.Monad.Reader
+import Control.Monad.State
 import Control.Monad.Trans.Control
 import Control.Monad.Trans.Elevator
-import Control.Monad.Writer.Class
+import Control.Monad.Writer
 import Data.Kind
 
+-- * 'ComposeT'
+--
+-- $composet
+--
+-- 'ComposeT' can be used in monad transformer stacks to derive instances in a clean way.
+--
+-- This also allows the usage of these instances, while in the middle of the transformer stack.
+-- This proves particularly useful, when writing a runner for a transformer stack.
+
 -- | A newtype wrapper for two stacked monad transformers.
 --
 -- Access instances of the intermediate monad @('t2' 'm')@, whenever 't1' implements
 -- 'MonadTrans'/'MonadTransControl'.
+--
+-- ==== Type level arguments
+-- [@'t1' :: ('Type' -> 'Type') -> 'Type' -> 'Type'@] outer monad transformer
+-- [@'t2' :: ('Type' -> 'Type') -> 'Type' -> 'Type'@] inner monad transformer
+-- [@'m' :: 'Type' -> 'Type'@] monad
+-- [@'a' :: 'Type'@] value
 type ComposeT :: ((Type -> Type) -> Type -> Type) -- ^ 't1'
               -> ((Type -> Type) -> Type -> Type) -- ^ 't2'
               -> (Type -> Type) -- ^ 'm'
@@ -57,38 +70,74 @@
     , MonadBaseControl b m
     ) => MonadBaseControl b (ComposeT t1 t2 m)
 
--- | Elevated to @('t2' 'm')@.
+-- | /OVERLAPPABLE/.
+-- Elevated to @('t2' 'm')@.
 deriving via Elevator t1 (t2 (m :: * -> *))
-  instance
+  instance {-# OVERLAPPABLE #-}
     ( Monad (t1 (t2 m))
     , MonadTransControl t1
     , MonadError e (t2 m)
     ) => MonadError e (ComposeT t1 t2 m)
 
--- | Elevated to @('t2' 'm')@.
-deriving via Elevator t1 (t2 (m :: * -> *))
+-- | Set by 'ExceptT'.
+deriving via ExceptT e (t2 (m :: * -> *))
   instance
+    ( Monad (t2 m)
+    ) => MonadError e ((ComposeT (ExceptT e) t2) m)
+
+-- | /OVERLAPPABLE/.
+-- Elevated to @('t2' 'm')@.
+deriving via Elevator t1 (t2 (m :: * -> *))
+  instance {-# OVERLAPPABLE #-}
     ( Monad (t1 (t2 m))
     , MonadTransControl t1
     , MonadReader r (t2 m)
     ) => MonadReader r (ComposeT t1 t2 m)
 
--- | Elevated to @('t2' 'm')@.
-deriving via Elevator t1 (t2 (m :: * -> *))
+-- | Set by 'ReaderT'.
+deriving via ReaderT r (t2 (m :: * -> *))
   instance
+    ( Monad (t2 m)
+    ) => MonadReader r ((ComposeT (ReaderT r) t2) m)
+
+-- | /OVERLAPPABLE/.
+-- Elevated to @('t2' 'm')@.
+deriving via Elevator t1 (t2 (m :: * -> *))
+  instance {-# OVERLAPPABLE #-}
     ( Monad (t1 (t2 m))
     , MonadTrans t1
     , MonadState s (t2 m)
     ) => MonadState s (ComposeT t1 t2 m)
 
--- | Elevated to @('t2' 'm')@.
-deriving via Elevator t1 (t2 (m :: * -> *))
+-- | Set by 'StateT'.
+deriving via StateT s (t2 (m :: * -> *))
   instance
+    ( Monad (t2 m)
+    ) => MonadState s ((ComposeT (StateT s) t2) m)
+
+-- | /OVERLAPPABLE/.
+-- Elevated to @('t2' 'm')@.
+deriving via Elevator t1 (t2 (m :: * -> *))
+  instance {-# OVERLAPPABLE #-}
     ( Monad (t1 (t2 m))
     , MonadTransControl t1
     , MonadWriter w (t2 m)
     ) => MonadWriter w (ComposeT t1 t2 m)
 
+-- | Set by 'WriterT'.
+deriving via WriterT w (t2 (m :: * -> *))
+  instance
+    ( Monad (t2 m)
+    , Monoid w
+    ) => MonadWriter w ((ComposeT (WriterT w) t2) m)
+
+
+-- ** Run 'ComposeT'
+--
+-- $runComposet
+--
+-- You have to run the composed monad transformers to get back into the base monad at some point.
+
 -- | Run a transformer stack.
 --
 -- This function takes the two individual monad transformer runners as arguments.
@@ -109,3 +158,126 @@
              -> (t2 m a -> m a) -- ^ run 't2'
              -> (ComposeT t1 t2 m a -> m a)
 runComposeT' runT1 runT2 = runT2 . runT1 . deComposeT
+
+-- * Examples
+
+-- ** Example 1: Create a new type class
+--
+-- $example1
+--
+-- When creating a new type class that supports 'ComposeT', you want to add recursive instances for
+-- `ComposeT`.
+--
+-- @
+-- class Monad m => MonadCustom m where
+--   simpleMethod :: a -> m a
+--   complicatedMethod :: (a -> m a) -> m a
+-- @
+--
+-- You can easily derive those instances, after implementing an instance for 'Elevator'.
+--
+-- Then it's possible to derive the recursive instance.
+-- This is an /OVERLAPPABLE/ instance, because we want to be able to add new instances through
+-- transformers in a stack.
+--
+-- @
+-- deriving via Elevator t1 (t2 (m :: * -> *))
+--   instance {-# OVERLAPPABLE #-}
+--     ( Monad (t1 (t2 m))
+--     , MonadTransControl t1
+--     , MonadCustom (t2 m)
+--     ) => MonadCustom (ComposeT t1 t2 m)
+-- @
+
+-- ** Example 2: Add an instance
+--
+-- $example2
+--
+-- Add a type class instance for a new monad transformer, when there already is a recursive instance for 'ComposeT'.
+--
+-- @
+-- newtype CustomT m a = CustomT { unCustomT :: IdentityT m a }
+--   deriving newtype (Functor, Applicative, Monad)
+--   deriving newtype (MonadTrans, MonadTransControl)
+-- @
+--
+-- First we need the regular instance.
+-- The method implementations are 'undefined' here, because they are not related to 'ComposeT'.
+--
+-- @
+-- instance Monad m => MonadCustom (CustomT m) where
+--   simpleMethod = undefined
+--   complicatedMethod = undefined
+-- @
+--
+-- To add an instance that takes priority over the recursive instance /FlexibleInstances/ are required.
+--
+-- @
+-- deriving via CustomT (t2 (m :: * -> *))
+--   instance
+--     ( Monad (t2 m)
+--     ) => MonadCustom ((ComposeT CustomT t2) m)
+-- @
+
+-- ** Example 3: Build a transformer stack
+--
+-- $example3
+--
+-- Create a monad transformer stack and wrap it using a newtype.
+--
+-- @
+-- type (|.) = ComposeT
+-- type Stack = StateT Int |. ReaderT Char |. CustomT |. ReaderT Bool |. IdentityT
+-- newtype StackT m a = StackT { unStackT :: Stack m a }
+--   deriving newtype (Functor, Applicative, Monad)
+-- @
+--
+-- We are adding 'IdentityT' to the stack, so that all the other transformer instances end up in the stack.
+-- Now we can simply derive just the instances, that we want.
+--
+-- @
+--   deriving newtype (MonadState Int)
+--   deriving newtype MonadCustom
+-- @
+--
+-- We can even use 'Elevator' to access instances, that have been shadowed in the stack.
+--
+-- @
+--   deriving (MonadReader Bool) via
+--     (           (StateT Int)
+--     ( Elevator  (ReaderT Char)
+--     (           CustomT
+--     (           ReaderT Bool
+--     (           IdentityT m)))))
+-- @
+
+-- ** Example 4: Run a transformer stack
+--
+-- $example4
+--
+-- This is the part, that actually contains your application logic.
+-- Because of the setup with `ComposeT`, we won't have to worry about 'lift'ing during the
+-- initialization.
+--
+-- @
+-- runStackT :: MonadBaseControl IO m
+--           => StackT m a
+--           -> m (StT StackT a)
+-- runStackT stackTma = do
+--   let
+--     runReaderT' :: MonadReader Bool m => ReaderT Char m a -> m a
+--     runReaderT' tma = do
+--       bool <- ask
+--       let char = if bool
+--                     then \'Y\'
+--                     else \'N\'
+--       runReaderT tma char
+--
+--     runStateT' :: MonadReader Char m => StateT Int m a -> m (a, Int)
+--     runStateT' tma = do
+--       char <- ask
+--       let num = fromEnum char
+--       runStateT tma num
+--
+--   runStateT' |. runReaderT' |. runCustomT |. (\\ tma -> runReaderT tma True) |. runIdentityT $ unStackT stackTma
+-- @
diff --git a/src/Control/Monad/Trans/Elevator.hs b/src/Control/Monad/Trans/Elevator.hs
--- a/src/Control/Monad/Trans/Elevator.hs
+++ b/src/Control/Monad/Trans/Elevator.hs
@@ -11,9 +11,23 @@
 import Control.Monad.Writer.Class
 import Data.Kind
 
+-- * 'Elevator'
+--
+-- $elevator
+--
+-- 'Elevator' can be used to lift instances through monad transformers as long as they implement
+-- 'MonadTrans' and 'MonadTransControl' instances.
+--
+-- 'MonadTransControl' is only necessary when there is atleast one method with a monadic argument.
+
 -- | A newtype wrapper for monad transformers.
 --
 -- Access instances of the inner monad 'm'.
+--
+-- ==== Type level arguments
+-- [@'t' :: ('Type' -> 'Type') -> 'Type' -> 'Type'@] monad transformer
+-- [@'m' :: 'Type' -> 'Type'@] monad
+-- [@'a' :: 'Type'@] value
 type Elevator :: ((Type -> Type) -> Type -> Type) -- ^ 't'
               -> (Type -> Type) -- ^ 'm'
               -> Type -- ^ 'a'
@@ -54,34 +68,36 @@
   pass tma = lift . pass . pure =<< tma
 
 -- * Examples
---
--- $examples
+
+-- ** Example 1: Recover submerged instances
 --
--- == Example 1: Recover submerged instances
+-- $example1
 --
 -- Let's assume you want to define a monad transformer stack.
 --
 -- @
 -- newtype StackT m a = StackT { unStackT :: ReaderT Char (ReaderT Bool m) a }
---   deriving newtype (Functor, Applicative Monad)
+--   deriving newtype (Functor, Applicative, Monad)
 -- @
 --
--- Now you want to expose the inner @(MonadReader Bool)@ instance with @(StackT m)@.
+-- Now you want to expose the inner @('MonadReader' 'Bool')@ instance with @(StackT m)@.
 --
--- Normally it's shadowed by the @(MonadReader Char)@ instance, but we can use @Elevator@ to access
+-- Normally it's shadowed by the @('MonadReader' 'Char')@ instance, but we can use 'Elevator' to access
 -- the inner transformer.
 --
 -- @
---   deriving (MonadReader Bool) via (Elevator (ReaderT Char) (ReaderT Bool m))
+--   deriving (MonadReader Bool) via Elevator (ReaderT Char) (ReaderT Bool m)
 -- @
+
+-- ** Example 2: Custom transformer without boilerplate
 --
--- == Example 2: Custom transformer without boilerplate
+-- $example2
 --
 -- Let's assume you have defined a monad transformer.
 --
 -- @
 -- newtype CustomT m a = CustomT { unComposeT :: IdentityT m a }
---   deriving newtype (Functor, Applicative Monad)
+--   deriving newtype (Functor, Applicative, Monad)
 --   deriving newtype (MonadTrans, MonadTransControl)
 --
 -- runCustomT :: CustomT m a -> m a
@@ -91,16 +107,47 @@
 -- Now you want to use this monad transformer in a transformer stack.
 --
 -- @
--- newtype StackT m a = { unStackT :: CustomT (ReaderT Bool m) a }
+-- newtype StackT m a = StackT { unStackT :: CustomT (ReaderT Bool m) a }
 --   deriving newtype (Functor, Applicative Monad)
---   deriving newtype (MonadTrans, MonadTransControl)
 -- @
 --
--- Unfortunately we can't derive a @Monad m => MonadReader Bool (StackT m)@ instance with
--- GeneralizedNewtypeDeriving, without also adding the instance to @CustomT@.
+-- Unfortunately we can't derive a @('Monad' m => 'MonadReader' 'Bool' (StackT m))@ instance with
+-- /GeneralizedNewtypeDeriving/, without also adding the instance to @CustomT@.
 --
--- To still derive this trivial instance we can use @Elevator@ with DerivingVia.
+-- To still derive this trivial instance we can use 'Elevator' with /DerivingVia/.
 --
 -- @
 --   deriving (MonadReader Bool) via (Elevator CustomT (ReaderT Bool m))
 -- @
+
+-- ** Example 3: Adding an instance for 'Elevator'
+--
+-- $example3
+--
+-- Suppose you define a new type class.
+--
+-- @
+-- class Monad m => MonadCustom m where
+--   simpleMethod :: a -> m a
+--   complicatedMethod :: (a -> m b) -> m b
+-- @
+--
+-- A simple way to allow a type class to be lifted through other monad transformers is by adding an
+-- instance for 'Elevator'.
+--
+-- You have to be careful about monadic state 'StT', when defining such instances using
+-- 'MonadTransControl'.
+--
+-- @
+-- instance (MonadCustom m, MonadTrans t) => MonadCustom (Elevator t m) where
+--   simpleMethod = lift . simpleMethod
+--   complicatedMethod f = (restoreT . pure =\<\<) $ liftWith $ \\ runT ->
+--     complicatedMethod $ runT . f
+-- @
+--
+-- Some useful examples (or exercises) are the instances for [mtl](https://hackage.haskell.org/package/mtl)'s type classes:
+--
+-- * 'MonadError'
+-- * 'MonadReader'
+-- * 'MonadState'
+-- * 'MonadWriter'
