diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,12 @@
 # Revision history for deriving-trans
 
+## 0.5.0.0 *25 Jul 2022*
+
+* Add module `Control.Monad.Trans.Compose.Infix`.
+* Add module `Control.Monad.Trans.Compose.Stack`.
+* Add module `Control.Monad.Trans.Compose.Transparent`.
+* Improve and update Haddock documentation and examples.
+
 ## 0.4.0.0 *18 Jul 2022*
 
 * Add dependency on monad-control-identity.
diff --git a/deriving-trans.cabal b/deriving-trans.cabal
--- a/deriving-trans.cabal
+++ b/deriving-trans.cabal
@@ -1,6 +1,6 @@
 cabal-version:       3.0
 name:                deriving-trans
-version:             0.4.0.0
+version:             0.5.0.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
@@ -27,6 +27,9 @@
 library
   exposed-modules:
     Control.Monad.Trans.Compose
+    Control.Monad.Trans.Compose.Infix
+    Control.Monad.Trans.Compose.Stack
+    Control.Monad.Trans.Compose.Transparent
     Control.Monad.Trans.Elevator
   --other-modules:
   build-depends:
@@ -61,6 +64,7 @@
     StandaloneKindSignatures
     TypeApplications
     TypeFamilies
+    TypeOperators
   ghc-options:
     -Wall
     -Wunused-packages
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
@@ -1,4 +1,5 @@
-{-# LANGUAGE QuantifiedConstraints, UndecidableInstances #-}
+{-# LANGUAGE QuantifiedConstraints #-}
+{-# LANGUAGE UndecidableInstances #-}
 
 module Control.Monad.Trans.Compose where
 
@@ -36,10 +37,11 @@
 
 -- | A newtype wrapper for two stacked monad transformers.
 --
--- Access instances of the intermediate monad @(t2 m)@, whenever @t1@ implements 'MonadTrans' /
--- 'MonadTransControl'.
+-- Access instances of the intermediate monad @(t2 m)@, whenever @t1@ implements 'MonadTrans' \/
+-- 'MonadTransControl' \/ 'MonadTransControlIdentity'.
 --
--- ==== Type level arguments
+-- __Type level arguments:__
+--
 -- [@t1 :: ('Type' -> 'Type') -> 'Type' -> 'Type'@] outer monad transformer
 -- [@t2 :: ('Type' -> 'Type') -> 'Type' -> 'Type'@] inner monad transformer
 -- [@m :: 'Type' -> 'Type'@] monad
@@ -257,7 +259,7 @@
 --
 -- You have to run the composed monad transformers to get back into the base monad at some point.
 
--- | Run a transformer stack.
+-- | Run two stacked monad transformers.
 --
 -- This function takes the two individual monad transformer runners as arguments.
 runComposeT :: (forall a. t1 (t2 m) a -> t2 m (StT t1 a)) -- ^ run @t1@
@@ -317,9 +319,9 @@
 -- for 'ComposeT'.
 --
 -- @
--- newtype CustomT m a = CustomT { unCustomT :: 'Control.Monad.Trans.Identity.IdentityT' m a }
+-- newtype CustomT m a = CustomT { unCustomT :: t'Control.Monad.Trans.Identity.IdentityT' m a }
 --   deriving newtype ('Functor', 'Applicative', 'Monad')
---   deriving newtype ('MonadTrans', 'MonadTransControl')
+--   deriving newtype ('MonadTrans', 'MonadTransControl', 'MonadTransControlIdentity')
 -- @
 --
 -- First we need the regular instance.
@@ -347,17 +349,18 @@
 -- Create a monad transformer stack and wrap it using a newtype.
 --
 -- @
--- type (|.) = 'ComposeT'
--- type Stack = 'LT.StateT' 'Int' |. 'T.ReaderT' 'Char' |. CustomT |. 'T.ReaderT' 'Bool' |. 'Control.Monad.Trans.Identity.IdentityT'
+-- type Stack = t'Control.Monad.Trans.Compose.Transparent.TransparentT' t'Control.Monad.Trans.Compose.Infix..|>' 'T.ReaderT' 'Bool' t'Control.Monad.Trans.Compose.Infix..|>' CustomT t'Control.Monad.Trans.Compose.Infix..|>' 'T.ReaderT' 'Char' t'Control.Monad.Trans.Compose.Infix..|>' 'LT.StateT' 'Int'
 -- newtype StackT m a = StackT { unStackT :: Stack m a }
 --   deriving newtype ('Functor', 'Applicative', 'Monad')
 -- @
 --
--- We are adding 'Control.Monad.Trans.Identity.IdentityT' to the end of the stack, so that all the
--- other transformer instances end up in the stack.
+-- Using t'Control.Monad.Trans.Compose.Infix..|>' we can write @Stack@ in the order of initialization.
+-- We are adding t'Control.Monad.Trans.Compose.Transparent.TransparentT' to the bottom of the stack,
+-- so that all the other transformer instances actually end up in the stack.
 -- Now we can simply derive just the instances, that we want.
 --
 -- @
+--   deriving newtype ('MonadTrans', 'MonadTransControl')
 --   deriving newtype ('MonadState' 'Int')
 --   deriving newtype MonadCustom
 -- @
@@ -375,29 +378,29 @@
 -- 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.
+-- With 'Control.Monad.Trans.Compose.Infix...>' we can use the order of initialization again.
 --
 -- @
 -- runStackT :: 'MonadBaseControl' 'IO' m
 --           => StackT m a
---           -> m (StT StackT a)
+--           -> m ('StT' StackT a)
 -- runStackT stackTma =
---   runStateT' |.
---     runReaderT' |.
---       runCustomT |.
---         (\\ tma -> 'T.runReaderT' tma 'True') |.
---           'Control.Monad.Trans.Identity.runIdentityT' $ unStackT stackTma
---   where
---     runReaderT' :: 'MonadReader' 'Bool' m => 'T.ReaderT' 'Char' m a -> m a
---     runReaderT' tma = do
---       bool <- 'ask'
---       let char = if bool
---                     then \'Y\'
---                     else \'N\'
---       'T.runReaderT' tma char
+--   'Control.Monad.Trans.Compose.Transparent.runTransparentT'
+--     'Control.Monad.Trans.Compose.Infix../>' (\\ tma -> 'T.runReaderT' tma 'True')
+--     'Control.Monad.Trans.Compose.Infix../>' runCustomT
+--     'Control.Monad.Trans.Compose.Infix../>' runReaderT'
+--     'Control.Monad.Trans.Compose.Infix../>' runStateT'
+--     $ unStackT stackTma
+--  where
+--   runReaderT' :: 'MonadReader' 'Bool' m => 'T.ReaderT' 'Char' m a -> m a
+--   runReaderT' tma = do
+--     bool <- 'ask'
+--     let char = if bool then \'Y\' else \'N\'
+--     'T.runReaderT' tma char
 --
---     runStateT' :: 'MonadReader' 'Char' m => 'LT.StateT' 'Int' m a -> m (a, 'Int')
---     runStateT' tma = do
---       char <- 'ask'
---       let num = 'fromEnum' char
---       'LT.runStateT' tma num
+--   runStateT' :: 'MonadReader' 'Char' m => 'LT.StateT' 'Int' m a -> m (a, 'Int')
+--   runStateT' tma = do
+--     char <- 'ask'
+--     let num = 'fromEnum' char
+--     'LT.runStateT' tma num
 -- @
diff --git a/src/Control/Monad/Trans/Compose/Infix.hs b/src/Control/Monad/Trans/Compose/Infix.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Monad/Trans/Compose/Infix.hs
@@ -0,0 +1,25 @@
+module Control.Monad.Trans.Compose.Infix where
+
+import Control.Monad.Trans.Compose
+import Control.Monad.Trans.Control
+
+-- | A flipped type-level infix operator for 'ComposeT'.
+type (.|>) t2 t1 = ComposeT t1 t2
+
+infixl 1 .|>
+
+-- | A 'flip'ped infix operator for 'runComposeT'.
+(./>) :: (forall a. t2 m a -> m (StT t2 a)) -- ^ run @t2@
+      -> (forall a. t1 (t2 m) a -> t2 m (StT t1 a)) -- ^ run @t1@
+      -> (forall a. (t2 .|> t1) m a -> m (StT t2 (StT t1 a)))
+(./>) runT2 runT1 = runComposeT runT1 runT2
+
+infixl 1 ./>
+
+-- | A 'flip'ped infix operator for 'runComposeT''.
+(..>) :: (t2 m a -> m a) -- ^ run @t2@
+      -> (t1 (t2 m) a -> t2 m a) -- ^ run @t1@
+      -> ((t2 .|> t1) m a -> m a)
+(..>) runT2 runT1 = runComposeT' runT1 runT2
+
+infixl 1 ..>
diff --git a/src/Control/Monad/Trans/Compose/Stack.hs b/src/Control/Monad/Trans/Compose/Stack.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Monad/Trans/Compose/Stack.hs
@@ -0,0 +1,131 @@
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE TypeFamilyDependencies #-}
+{-# LANGUAGE UndecidableInstances #-}
+{-# OPTIONS -Wno-unticked-promoted-constructors #-}
+
+-- | This module gives an alternative interface to build and run monad transformer stacks.
+--
+-- Using this approach is supposed to improve error messages and reduce errors, such as forgetting
+-- to add 'TransparentT' at the bottom of the stack.
+module Control.Monad.Trans.Compose.Stack where
+
+import Control.Monad.Trans.Compose
+import Control.Monad.Trans.Compose.Transparent
+import Data.Kind
+
+-- * 'StackT'
+--
+-- $stackt
+--
+-- 'StackT' is a more ergonomic way to define a monad transformer stack.
+
+-- | An isomorphism between a 'Stack' and the corresponding monad transformer, which can be built
+-- using 'ComposeT'.
+--
+-- An additional 'TransparentT' will automatically be used at the bottom of the stack.
+-- You only have to worry about the semantically relevant transformers.
+type family StackT (ts :: Stack) = (t :: (Type -> Type) -> Type -> Type) | t -> ts where
+  StackT NilT = TransparentT
+  StackT (ts :.|> t) = ComposeT t (StackT ts)
+
+-- ** 'runStackT' and 'RunStackT'
+--
+-- $runStackt
+--
+-- Monad transformer stacks, that only consist of t'Control.Monad.Trans.Identity.IdentityT' and
+-- t'Control.Monad.Trans.Reader.ReaderT', can be run with 'runStackT'.
+--
+-- If your transformer stack contains monadic state t'Control.Monad.Trans.Control.StT', you will have to use 'runComposeT' or 'Control.Monad.Trans.Compose.Infix../>'!
+-- You can still use 'StackT' for the type definition.
+
+-- | Run a monad transformer stack.
+--
+-- This takes a 'RunStackT' as an argument containing the individual runners.
+--
+-- 'runStackT' can only be used for monad transformer stacks without monadic state t'Control.Monad.Trans.Control.StT'.
+runStackT :: RunStackT ts m a -> StackT ts m a -> m a
+runStackT RunNilT = runTransparentT
+runStackT (runRemainingStackT :..> runNextT) = runStackT runRemainingStackT . runNextT . deComposeT
+
+-- | A data type representing the runner function of a monad transformer stack.
+--
+-- This is basically a heterogeneous list of monad transformer runners.
+--
+-- 'RunStackT' can only be used for monad transformer stacks without monadic state t'Control.Monad.Trans.Control.StT'.
+data RunStackT :: Stack -> (Type -> Type) -> Type -> Type where
+  -- | run an empty monad transformer stack
+  RunNilT :: RunStackT NilT m a
+  -- | run the next monad transformer on a stack
+  (:..>) :: RunStackT ts m a -- ^ run remaining stack
+         -> (t (StackT ts m) a -> StackT ts m a) -- ^ run next monad transformer
+         -> RunStackT (ts :.|> t) m a
+
+infixl 1 :..>
+
+-- * 'Stack'
+--
+-- $stack
+--
+-- 'Stack' is used to define monad transformer stacks with 'StackT'.
+
+-- | A data kind representing a monad transformer stack.
+--
+-- This is basically a type-level list of monad transformers.
+data Stack where
+  -- | an empty monad transformer stack
+  NilT :: Stack
+  -- | add a monad transformer to a stack
+  (:.|>) :: Stack -- ^ remaining stack
+         -> ((Type -> Type) -> Type -> Type) -- ^ next monad transformer
+         -> Stack
+
+infixl 1 :.|>
+
+-- * Examples
+--
+-- $examples
+--
+-- Feel free to compare these examples to the ones in "Control.Monad.Trans.Compose".
+
+-- TODO: Qualified identifiers such as 'Control.Monad.Trans.Class.MonadTrans' need a "t"-prefix to
+--       work correctly, but it doesn't work with a leading opening parenthesis "(".
+
+-- ** Example 1: Build a transformer stack
+--
+-- $example1
+--
+-- Apply the type family 'StackT' to a type of kind 'Stack' and generate a monad transformer stack built with 'ComposeT'.
+--
+-- @
+-- type AppStack = 'NilT' ':.|>' t'Control.Monad.Trans.Reader.ReaderT' 'Bool' ':.|>' CustomT ':.|>' t'Control.Monad.Trans.Reader.ReaderT' 'Char'
+-- newtype AppStackT m a = AppStackT { unAppStackT :: StackT AppStack m a }
+--   deriving newtype ('Functor', 'Applicative', 'Monad')
+--   deriving newtype ('Control.Monad.Trans.Class.MonadTrans', t'Control.Monad.Trans.Control.MonadTransControl', t'Control.Monad.Trans.Control.Identity.MonadTransControlIdentity')
+--   deriving newtype MonadCustom
+--   deriving newtype ('Control.Monad.Reader.Class.MonadReader' 'Bool')
+-- @
+
+-- ** Example 2: Run a transformer stack
+--
+-- $example2
+--
+-- Use 'runStackT' and supply it with a 'RunStackT' argument.
+--
+-- @
+-- runAppStackT :: t'Control.Monad.Trans.Control.MonadBaseControl' 'IO' m
+--              => AppStackT m a
+--              -> m a
+-- runAppStackT stackTma = runStackT runAccStackT $ unStackT stackTma
+--  where
+--   runAccStackT :: RunStackT AppStack
+--   runAccStackT = RunNilT
+--     :..> (\\ tma -> 'Control.Monad.Trans.Reader.runReaderT' tma 'True')
+--     :..> runCustomT
+--     :..> runReaderT'
+--
+--   runReaderT' :: t'Control.Monad.Reader.Class.MonadReader' 'Bool' m => t'Control.Monad.Trans.Reader.ReaderT' 'Char' m a -> m a
+--   runReaderT' tma = do
+--     bool <- 'ask'
+--     let char = if bool then \'Y\' else \'N\'
+--     'Control.Monad.Trans.Reader.runReaderT' tma char
+-- @
diff --git a/src/Control/Monad/Trans/Compose/Transparent.hs b/src/Control/Monad/Trans/Compose/Transparent.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Monad/Trans/Compose/Transparent.hs
@@ -0,0 +1,27 @@
+{-# LANGUAGE UndecidableInstances #-}
+
+module Control.Monad.Trans.Compose.Transparent where
+
+import Control.Monad.Trans.Class
+import Control.Monad.Trans.Control
+import Control.Monad.Trans.Control.Identity
+import Control.Monad.Trans.Elevator
+import Control.Monad.Trans.Identity
+
+-- | A monad transformer, that passes through all instances via 'Elevator'.
+--
+-- This cannot be defined as a newtype, because we want all the instances, that are defined for
+-- 'Elevator' to work for 'TransparentT'.
+type TransparentT = Elevator NoT
+
+runTransparentT :: TransparentT m a -> m a
+runTransparentT = runIdentityT . unNoT . descend
+
+-- | A newtype wrapper around 'IdentityT'.
+--
+-- This is used in 'TransparentT' to encourage the use of 'runTransparentT'.
+newtype NoT m a = MkNoT {unNoT :: IdentityT m a}
+  deriving newtype (Functor, Applicative, Monad)
+  deriving newtype (MonadTrans, MonadTransControl, MonadTransControlIdentity)
+
+{-# WARNING NoT, MkNoT, unNoT "This is an implementation detail of 'TransparentT'." #-}
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
@@ -1,4 +1,6 @@
-{-# LANGUAGE QuantifiedConstraints, UndecidableInstances, TupleSections #-}
+{-# LANGUAGE QuantifiedConstraints #-}
+{-# LANGUAGE UndecidableInstances #-}
+{-# LANGUAGE TupleSections #-}
 
 module Control.Monad.Trans.Elevator where
 
@@ -23,15 +25,17 @@
 -- $elevator
 --
 -- 'Elevator' can be used to lift instances through monad transformers as long as they implement
--- 'MonadTrans' and 'MonadTransControl' instances.
+-- a 'MonadTrans' \/ 'MonadTransControl' \/ 'MonadTransControlIdentity' instance.
 --
 -- 'MonadTransControl' is only necessary when there is atleast one method with a monadic argument.
+-- 'MonadTransControlIdentity' is even stronger and only required for a few specific instances.
 
 -- | A newtype wrapper for monad transformers.
 --
 -- Access instances of the inner monad @m@.
 --
--- ==== Type level arguments
+-- __Type level arguments:__
+--
 -- [@t :: ('Type' -> 'Type') -> 'Type' -> 'Type'@] monad transformer
 -- [@m :: 'Type' -> 'Type'@] monad
 -- [@a :: 'Type'@] value
