diff --git a/CHANGELOG.markdown b/CHANGELOG.markdown
--- a/CHANGELOG.markdown
+++ b/CHANGELOG.markdown
@@ -1,5 +1,46 @@
-2.2.2
+2.3.2 -- 2025-12-07
 -----
+* Add `Accum` monad.
+* Generalize `MonadAccum` instance for all `Monad m` underlying `AccumT`, not just `Identity`.
+* Allow building monokinded `ContT` if the compiler is MicroHs.
+* Fix an issue where `QuantifiedConstraints` in the definition of `liftCallCC` was was preventing building under certain conditions.
+* Add `Control.Monad.Class.onError`.
+* Add various instances for `Data.Functor.Product.Product`.
+
+2.3.1 -- 2022-09-10
+-----
+* Add `modifyError` to `Control.Monad.Error.Class`, and re-export from
+  `Control.Monad.Except`.
+* Make the `MonadCont` instance for `ContT` more polykinded; now, `r` is allowed
+  to be of an arbitrary kind `k`, rather than only `Type`.
+* Add a generic `liftCallCC` for use with any `MonadTrans`.
+* Add `modifyError` to `Control.Monad.Error.Class`
+* Return re-export of `ExceptT` and related functions to `Control.Monad.Except`.
+* Add `label` function to `MonadCont`
+
+2.3 -- 2022-05-07
+---
+* Add instances for `Control.Monad.Trans.Writer.CPS` and
+  `Control.Monad.Trans.RWS.CPS` from `transformers` 0.5.6 and add
+  `Control.Monad.Writer.CPS` and `Control.Monad.RWS.CPS`.
+* `Control.Monad.Cont` now re-exports `evalCont` and `evalContT`.
+* Add `tryError`, `withError`, `handleError`, and `mapError` to
+  `Control.Monad.Error.Class`, and re-export from `Control.Monad.Except`.
+* Remove `Control.Monad.List` and `Control.Monad.Error`.
+* Remove instances of deprecated `ListT` and `ErrorT`.
+* Remove re-exports of `Error`.
+* Add instances for `Control.Monad.Trans.Accum` and
+  `Control.Monad.Trans.Select`.
+* Require GHC 8.6 or higher, and `cabal-install` 3.0 or higher.
+* Require `transformers-0.5.6` or higher.
+* Add `Control.Monad.Accum` for the `MonadAccum` type class, as well as the
+  `LiftingAccum` deriving helper.
+* Add `Control.Monad.Select` for the `MonadSelect` type class, as well as the
+  `LiftingSelect` deriving helper.
+* Remove re-exports of `Control.Monad`, `Control.Monad.Fix` and `Data.Monoid` modules
+
+2.2.2 -- 2018-02-24
+-----
 * `Control.Monad.Identity` now re-exports `Control.Monad.Trans.Identity`
 * Fix a bug in which `Control.Monad.State.Class.modify'` was not as strict in
   the new state as its counterparts in `transformers`
@@ -8,24 +49,24 @@
   `Control.Monad.Except{.Class}`
 * Add a `MonadWriter w ((,) w)` instance (when built against `base-4.9` or later)
 
-2.2.1
+2.2.1 -- 2014-06-02
 -------
 * Provide MINIMAL pragmas for `MonadState`, `MonadWriter`, `MonadReader`
 * Added a cyclic definition of `ask` in terms of `reader` for consistency with `get`/`put` vs. `state` and `tell` vs. `writer`
 * Fix deprecation warnings caused by `transformers` 0.4 deprecating `ErrorT`.
 * Added `Control.Monad.Except` in the style of the other `mtl` re-export modules
 
-2.2.0.1
+2.2.0.1 -- 2014-05-05
 -------
 * Fixed a bug caused by the change in how `transformers` 0.4 exports its data types. We will now export `runFooT` for each transformer again!
 
-2.2
+2.2 -- 2014-05-05
 ---
 * `transformers` 0.4 support
 * Added instances for `ExceptT`
 * Added `modify'` to `Control.Monad.State.*`
 
-2.1.3.1
+2.1.3.1 -- 2014-03-24
 -------
 * Avoid importing `Control.Monad.Instances` on GHC 7.8 to build without deprecation warnings.
 
diff --git a/Control/Monad/Accum.hs b/Control/Monad/Accum.hs
new file mode 100644
--- /dev/null
+++ b/Control/Monad/Accum.hs
@@ -0,0 +1,328 @@
+{-# LANGUAGE DerivingVia #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE FunctionalDependencies #-}
+{-# LANGUAGE KindSignatures #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE StandaloneDeriving #-}
+{-# LANGUAGE Trustworthy #-}
+{-# LANGUAGE TupleSections #-}
+{-# LANGUAGE UndecidableInstances #-}
+-- Later GHCs infer DerivingVia as not Safe
+-- We just downgrade to Trustworthy and go fish
+{-# OPTIONS_GHC -Wno-trustworthy-safe #-}
+
+-- | Module: Control.Monad.Accum
+-- Copyright: (C) Koz Ross 2022, Manuel Bärenz 2021
+-- License: BSD-3-Clause (see the LICENSE file)
+-- Maintainer: koz.ross@retro-freedom.nz
+-- Stability: Experimental
+-- Portability: GHC only
+--
+-- [Computation type:] Accumulation (either append-only state, or writer with
+-- the ability to read all previous input).
+--
+-- [Binding strategy:] Binding a function to a monadic value monoidally
+-- accumulates the subcomputations (that is, using '<>').
+--
+-- [Useful for:] Logging, patch-style tracking.
+--
+-- [Zero and plus:] None.
+--
+-- [Example type:] @'Control.Monad.Trans.Accum.Accum' w a@
+--
+-- = A note on commutativity
+--
+-- Some effects are /commutative/: it doesn't matter which you resolve first, as
+-- all possible orderings of commutative effects are isomorphic. Consider, for
+-- example, the reader and state effects, as exemplified by 'ReaderT' and
+-- 'StrictState.StateT' respectively. If we have
+-- @'ReaderT' r ('StrictState.State' s) a@, this is
+-- effectively @r -> 'StrictState.State' s a ~ r -> s -> (a, s)@; if we instead have
+-- @'StrictState.StateT' s ('Control.Monad.Trans.Reader.Reader' r) a@, this is effectively
+-- @s -> 'Control.Monad.Trans.Reader' r (a, s) ~ s -> r -> (a, s)@. Since we
+-- can always reorder function arguments (for example, using 'flip', as in
+-- this case) without changing the result, these are
+-- isomorphic, showing that reader and state are /commutative/, or, more
+-- precisely, /commute with each other/.
+--
+-- However, this isn't generally the case. Consider instead the error and state
+-- effects, as exemplified by 'MaybeT' and 'StrictState.StateT' respectively.
+-- If we have @'MaybeT' ('Control.Monad.Trans.State.Strict.State' s) a@, this
+-- is effectively @'State' s ('Maybe' a) ~ s -> ('Maybe' a, s)@: put simply,
+-- the error can occur only in the /result/, but
+-- not the state, which always \'survives\'. On the other hand, if we have
+-- @'StrictState.StateT' s 'Maybe' a@, this is instead @s -> 'Maybe' (a, s)@: here,
+-- if we error, we lose /both/ the state and the result! Thus, error and state effects
+-- do /not/ commute with each other.
+--
+-- As the MTL is capability-based, we support any ordering of non-commutative
+-- effects on an equal footing. Indeed, if you wish to use
+-- 'Control.Monad.State.Class.MonadState', for
+-- example, whether your final monadic stack ends up being @'MaybeT'
+-- ('Control.Monad.Trans.State.Strict.State' s)
+-- a@, @'StrictState.StateT' s 'Maybe' a@, or anything else, you will be able to write your
+-- desired code without having to consider such differences. However, the way we
+-- /implement/ these capabilities for any given transformer (or rather, any
+-- given transformed stack) /is/ affected by this ordering unless the effects in
+-- question are commutative.
+--
+-- We note in this module which effects the accumulation effect does and doesn't
+-- commute with; we also note on implementations with non-commutative
+-- transformers what the outcome will be. Note that, depending on how the
+-- \'inner monad\' is structured, this may be more complex than we note: we
+-- describe only what impact the \'outer effect\' has, not what else might be in
+-- the stack.
+--
+-- = Commutativity of accumulation
+--
+-- The accumulation effect commutes with the identity effect ('IdentityT'),
+-- reader, writer or state effects ('ReaderT', 'StrictWriter.WriterT', 'StrictState.StateT' and any
+-- combination, including 'StrictRWS.RWST' for example) and with itself. It does /not/
+-- commute with anything else.
+module Control.Monad.Accum
+  ( -- * Type class
+    MonadAccum (..),
+
+    -- * The 'Accum' monad
+    Accum.Accum,
+    Accum.runAccum,
+    Accum.execAccum,
+    Accum.evalAccum,
+    Accum.mapAccum,
+
+    -- * The 'AccumT' monad transformer
+    Accum.AccumT (..),
+    Accum.execAccumT,
+    Accum.evalAccumT,
+    Accum.mapAccumT,
+    Accum.readerToAccumT,
+    Accum.writerToAccumT,
+    Accum.accumToStateT,
+
+    -- * Lifting helper type
+    LiftingAccum (..),
+
+    -- * Other functions
+    looks,
+  )
+where
+
+import Control.Monad.Trans.Accum (AccumT)
+import qualified Control.Monad.Trans.Accum as Accum
+import Control.Monad.Trans.Class (MonadTrans (lift))
+import Control.Monad.Trans.Cont (ContT)
+import Control.Monad.Trans.Except (ExceptT)
+import Control.Monad.Trans.Identity (IdentityT)
+import Control.Monad.Trans.Maybe (MaybeT)
+import qualified Control.Monad.Trans.RWS.CPS as CPSRWS
+import qualified Control.Monad.Trans.RWS.Lazy as LazyRWS
+import qualified Control.Monad.Trans.RWS.Strict as StrictRWS
+import Control.Monad.Trans.Reader (ReaderT)
+import Control.Monad.Trans.Select (SelectT)
+import qualified Control.Monad.Trans.State.Lazy as LazyState
+import qualified Control.Monad.Trans.State.Strict as StrictState
+import qualified Control.Monad.Trans.Writer.CPS as CPSWriter
+import qualified Control.Monad.Trans.Writer.Lazy as LazyWriter
+import qualified Control.Monad.Trans.Writer.Strict as StrictWriter
+import Data.Functor (($>))
+import Data.Kind (Type)
+
+-- | The capability to accumulate. This can be seen in one of two ways:
+--
+-- * A 'Control.Monad.State.Class.MonadState' which can only append (using '<>'); or
+-- * A 'Control.Monad.Writer.Class.MonadWriter' (limited to
+-- 'Control.Monad.Writer.Class.tell') with the ability to view the result of all previous
+-- 'Control.Monad.Writer.Class.tell's.
+--
+-- = Laws
+--
+-- 'accum' should obey the following:
+--
+-- 1. @'accum' ('const' (x, 'mempty'))@ @=@ @'pure' x@
+-- 2. @'accum' f '*>' 'accum' g@ @=@
+-- @'accum' '$' \\acc -> let (_, v) = f acc
+--                          (res, w) = g (acc '<>' v) in (res, v '<>' w)@
+--
+-- If you choose to define 'look' and 'add' instead, their definitions must obey
+-- the following:
+--
+-- 1. @'look' '*>' 'look'@ @=@ @'look'@
+-- 2. @'add' 'mempty'@ @=@ @'pure' ()@
+-- 3. @'add' x '*>' 'add' y@ @=@ @'add' (x '<>' y)@
+-- 4. @'add' x '*>' 'look'@ @=@ @'look' '>>=' \\w -> 'add' x '$>' w '<>' x@
+--
+-- If you want to define both, the relationship between them is as follows.
+-- These are also the default definitions.
+--
+-- 1. @'look'@ @=@ @'accum' '$' \\acc -> (acc, mempty)@
+-- 2. @'add' x@ @=@ @'accum' '$' \\acc -> ('()', x)@
+-- 3. @'accum' f@ @=@ @'look' >>= \\acc -> let (res, v) = f acc in 'add' v '$>' res@
+--
+-- @since 2.3
+class (Monoid w, Monad m) => MonadAccum w m | m -> w where
+  -- | Retrieve the accumulated result so far.
+  look :: m w
+  look = accum (,mempty)
+
+  -- | Append a value to the result.
+  add :: w -> m ()
+  add x = accum $ const ((), x)
+
+  -- | Embed a simple accumulation action into the monad.
+  accum :: (w -> (a, w)) -> m a
+  accum f = look >>= \acc -> let (res, v) = f acc in add v $> res
+
+  {-# MINIMAL accum | look, add #-}
+
+-- | @since 2.3
+instance (Monoid w, Monad m) => MonadAccum w (AccumT w m) where
+  look = Accum.look
+  add = Accum.add
+  accum = Accum.accum
+
+-- | The accumulated value \'survives\' an error: even if the
+-- computation fails to deliver a result, we still have an accumulated value.
+--
+-- @since 2.3
+deriving via
+  (LiftingAccum MaybeT m)
+  instance
+    (MonadAccum w m) =>
+    MonadAccum w (MaybeT m)
+
+-- | The continuation can see, and interact with, the accumulated value.
+--
+-- @since 2.3
+deriving via
+  (LiftingAccum (ContT r) m)
+  instance
+    (MonadAccum w m) =>
+    MonadAccum w (ContT r m)
+
+-- | The accumulated value \'survives\' an exception: even if the computation
+-- fails to deliver a result, we still have an accumulated value.
+--
+-- @since 2.3
+deriving via
+  (LiftingAccum (ExceptT e) m)
+  instance
+    (MonadAccum w m) =>
+    MonadAccum w (ExceptT e m)
+
+-- | @since 2.3
+deriving via
+  (LiftingAccum IdentityT m)
+  instance
+    (MonadAccum w m) =>
+    MonadAccum w (IdentityT m)
+
+-- | @since 2.3
+deriving via
+  (LiftingAccum (CPSRWS.RWST r w s) m)
+  instance
+    (MonadAccum w' m) =>
+    MonadAccum w' (CPSRWS.RWST r w s m)
+
+-- | @since 2.3
+deriving via
+  (LiftingAccum (LazyRWS.RWST r w s) m)
+  instance
+    (MonadAccum w' m, Monoid w) =>
+    MonadAccum w' (LazyRWS.RWST r w s m)
+
+-- | @since 2.3
+deriving via
+  (LiftingAccum (StrictRWS.RWST r w s) m)
+  instance
+    (MonadAccum w' m, Monoid w) =>
+    MonadAccum w' (StrictRWS.RWST r w s m)
+
+-- | @since 2.3
+deriving via
+  (LiftingAccum (ReaderT r) m)
+  instance
+    (MonadAccum w m) =>
+    MonadAccum w (ReaderT r m)
+
+-- | The \'ranking\' function gains the ability to accumulate @w@s each time it
+-- is called. The final result will include the entire log of all such calls.
+--
+-- @since 2.3
+deriving via
+  (LiftingAccum (SelectT r) m)
+  instance
+    (MonadAccum w m) =>
+    MonadAccum w (SelectT r m)
+
+-- | @since 2.3
+deriving via
+  (LiftingAccum (LazyState.StateT s) m)
+  instance
+    (MonadAccum w m) =>
+    MonadAccum w (LazyState.StateT s m)
+
+-- | @since 2.3
+deriving via
+  (LiftingAccum (StrictState.StateT s) m)
+  instance
+    (MonadAccum w m) =>
+    MonadAccum w (StrictState.StateT s m)
+
+-- | @since 2.3
+deriving via
+  (LiftingAccum (CPSWriter.WriterT w) m)
+  instance
+    (MonadAccum w' m) =>
+    MonadAccum w' (CPSWriter.WriterT w m)
+
+-- | @since 2.3
+deriving via
+  (LiftingAccum (LazyWriter.WriterT w) m)
+  instance
+    (MonadAccum w' m, Monoid w) =>
+    MonadAccum w' (LazyWriter.WriterT w m)
+
+-- | @since 2.3
+deriving via
+  (LiftingAccum (StrictWriter.WriterT w) m)
+  instance
+    (MonadAccum w' m, Monoid w) =>
+    MonadAccum w' (StrictWriter.WriterT w m)
+
+-- | A helper type to decrease boilerplate when defining new transformer
+-- instances of 'MonadAccum'.
+--
+-- Most of the instances in this module are derived using this method; for
+-- example, our instance of 'ExceptT' is derived as follows:
+--
+-- > deriving via (LiftingAccum (ExceptT e) m) instance (MonadAccum w m) =>
+-- >  MonadAccum w (ExceptT e m)
+--
+-- @since 2.3
+newtype LiftingAccum (t :: (Type -> Type) -> Type -> Type) (m :: Type -> Type) (a :: Type)
+  = LiftingAccum (t m a)
+  deriving
+    ( -- | @since 2.3
+      Functor,
+      -- | @since 2.3
+      Applicative,
+      -- | @since 2.3
+      Monad
+    )
+    via (t m)
+
+-- | @since 2.3
+instance (MonadTrans t, Monad (t m), MonadAccum w m) => MonadAccum w (LiftingAccum t m) where
+  look = LiftingAccum . lift $ look
+  add x = LiftingAccum . lift $ add x
+  accum f = LiftingAccum . lift $ accum f
+
+-- | Retrieve a function of the accumulated value.
+--
+-- @since 2.3
+looks ::
+  forall (a :: Type) (m :: Type -> Type) (w :: Type).
+  (MonadAccum w m) =>
+  (w -> a) ->
+  m a
+looks f = f <$> look
diff --git a/Control/Monad/Cont.hs b/Control/Monad/Cont.hs
--- a/Control/Monad/Cont.hs
+++ b/Control/Monad/Cont.hs
@@ -1,3 +1,5 @@
+{-# LANGUAGE Safe #-}
+
 {- |
 Module      :  Control.Monad.Cont
 Copyright   :  (c) The University of Glasgow 2001,
@@ -50,36 +52,38 @@
 
 module Control.Monad.Cont (
     -- * MonadCont class
-    MonadCont(..),
+    MonadCont.MonadCont(..),
+    MonadCont.label,
+    MonadCont.label_,
+
     -- * The Cont monad
-    Cont,
-    cont,
-    runCont,
-    mapCont,
-    withCont,
+    Cont.Cont,
+    Cont.cont,
+    Cont.runCont,
+    Cont.evalCont,
+    Cont.mapCont,
+    Cont.withCont,
     -- * The ContT monad transformer
-    ContT(ContT),
-    runContT,
-    mapContT,
-    withContT,
-    module Control.Monad,
-    module Control.Monad.Trans,
+    Cont.ContT(ContT),
+    Cont.runContT,
+    Cont.evalContT,
+    Cont.mapContT,
+    Cont.withContT,
     -- * Example 1: Simple Continuation Usage
     -- $simpleContExample
 
     -- * Example 2: Using @callCC@
     -- $callCCExample
-    
+
     -- * Example 3: Using @ContT@ Monad Transformer
     -- $ContTExample
-  ) where
 
-import Control.Monad.Cont.Class
-
-import Control.Monad.Trans
-import Control.Monad.Trans.Cont
+    -- * Example 4: Using @label@
+    -- $labelExample
+  ) where
 
-import Control.Monad
+import qualified Control.Monad.Cont.Class as MonadCont
+import qualified Control.Monad.Trans.Cont as Cont
 
 {- $simpleContExample
 Calculating length of a list continuation-style:
@@ -166,4 +170,20 @@
 @askString@ takes as a parameter a continuation taking a string parameter,
 and returning @IO ()@.
 Compare its signature to 'runContT' definition.
+-}
+
+{-$labelExample
+
+The early exit behavior of 'Control.Monad.Cont.Class.callCC' can be leveraged to produce other idioms:
+
+> whatsYourNameLabel :: IO ()
+> whatsYourNameLabel = evalContT $ do
+>   (beginning, attempts) <- label (0 :: Int)
+>   liftIO $ putStrLn $ "Attempt #" <> show attempts
+>   liftIO $ putStrLn $ "What's your name?"
+>   name <- liftIO getLine
+>   when (null name) $ beginning (attempts + 1)
+>   liftIO $ putStrLn $ "Welcome, " ++ name ++ "!"
+
+Calling @beggining@ will interrupt execution of the block, skipping the welcome message, which will be printed only once at the very end of the loop.
 -}
diff --git a/Control/Monad/Cont/Class.hs b/Control/Monad/Cont/Class.hs
--- a/Control/Monad/Cont/Class.hs
+++ b/Control/Monad/Cont/Class.hs
@@ -1,4 +1,13 @@
 {-# LANGUAGE CPP #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE Safe #-}
+{-# LANGUAGE PolyKinds #-}
+{-# LANGUAGE QuantifiedConstraints #-}
+-- Needed because the CPSed versions of Writer and State are secretly State
+-- wrappers, which don't force such constraints, even though they should legally
+-- be there.
+{-# OPTIONS_GHC -Wno-redundant-constraints #-}
+
 {- |
 Module      :  Control.Monad.Cont.Class
 Copyright   :  (c) The University of Glasgow 2001,
@@ -51,35 +60,46 @@
 
 module Control.Monad.Cont.Class (
     MonadCont(..),
+    label,
+    label_,
+    liftCallCC,
   ) where
 
+import Data.Kind (Type)
+import Control.Monad.Fix (fix)
 import Control.Monad.Trans.Cont (ContT)
 import qualified Control.Monad.Trans.Cont as ContT
-import Control.Monad.Trans.Error as Error
-import Control.Monad.Trans.Except as Except
-import Control.Monad.Trans.Identity as Identity
-import Control.Monad.Trans.List as List
-import Control.Monad.Trans.Maybe as Maybe
-import Control.Monad.Trans.Reader as Reader
-import Control.Monad.Trans.RWS.Lazy as LazyRWS
-import Control.Monad.Trans.RWS.Strict as StrictRWS
-import Control.Monad.Trans.State.Lazy as LazyState
-import Control.Monad.Trans.State.Strict as StrictState
-import Control.Monad.Trans.Writer.Lazy as LazyWriter
-import Control.Monad.Trans.Writer.Strict as StrictWriter
-
-import Control.Monad
-import Data.Monoid
+import Control.Monad.Trans.Except (ExceptT)
+import qualified Control.Monad.Trans.Except as Except
+import Control.Monad.Trans.Identity (IdentityT)
+import qualified Control.Monad.Trans.Identity as Identity
+import Control.Monad.Trans.Maybe (MaybeT)
+import qualified Control.Monad.Trans.Maybe as Maybe
+import Control.Monad.Trans.Reader (ReaderT)
+import qualified Control.Monad.Trans.Reader as Reader
+import qualified Control.Monad.Trans.RWS.Lazy as LazyRWS
+import qualified Control.Monad.Trans.RWS.Strict as StrictRWS
+import qualified Control.Monad.Trans.State.Lazy as LazyState
+import qualified Control.Monad.Trans.State.Strict as StrictState
+import qualified Control.Monad.Trans.Writer.Lazy as LazyWriter
+import qualified Control.Monad.Trans.Writer.Strict as StrictWriter
+import Control.Monad.Trans.Accum (AccumT)
+import qualified Control.Monad.Trans.Accum as Accum
+import qualified Control.Monad.Trans.RWS.CPS as CPSRWS
+import qualified Control.Monad.Trans.Writer.CPS as CPSWriter
+import Control.Monad.Trans.Class (MonadTrans (lift))
+import Control.Monad.Signatures (CallCC)
+import Control.Monad (join)
 
-class Monad m => MonadCont m where
+class Monad m => MonadCont (m :: Type -> Type) where
     {- | @callCC@ (call-with-current-continuation)
     calls a function with the current continuation as its argument.
     Provides an escape continuation mechanism for use with Continuation monads.
     Escape continuations allow to abort the current computation and return
     a value immediately.
-    They achieve a similar effect to 'Control.Monad.Error.throwError'
-    and 'Control.Monad.Error.catchError'
-    within an 'Control.Monad.Error.Error' monad.
+    They achieve a similar effect to 'Control.Monad.Error.Class.throwError'
+    and 'Control.Monad.Error.Class.catchError'
+    within an 'Control.Monad.Except.Except' monad.
     Advantage of this function over calling @return@ is that it makes
     the continuation explicit,
     allowing more flexibility and better control
@@ -91,29 +111,27 @@
     even if it is many layers deep within nested computations.
     -}
     callCC :: ((a -> m b) -> m a) -> m a
-#if __GLASGOW_HASKELL__ >= 707
     {-# MINIMAL callCC #-}
-#endif
 
+-- | @since 2.3.1
+#ifdef __MHS__
+-- The ContT type is not polykinded with mhs.
 instance MonadCont (ContT r m) where
+#else
+instance forall k (r :: k) (m :: (k -> Type)) . MonadCont (ContT r m) where
+#endif
     callCC = ContT.callCC
 
 -- ---------------------------------------------------------------------------
 -- Instances for other mtl transformers
 
-instance (Error e, MonadCont m) => MonadCont (ErrorT e m) where
-    callCC = Error.liftCallCC callCC
-
-{- | @since 2.2 -}
+-- | @since 2.2
 instance MonadCont m => MonadCont (ExceptT e m) where
     callCC = Except.liftCallCC callCC
 
 instance MonadCont m => MonadCont (IdentityT m) where
     callCC = Identity.liftCallCC callCC
 
-instance MonadCont m => MonadCont (ListT m) where
-    callCC = List.liftCallCC callCC
-
 instance MonadCont m => MonadCont (MaybeT m) where
     callCC = Maybe.liftCallCC callCC
 
@@ -137,3 +155,66 @@
 
 instance (Monoid w, MonadCont m) => MonadCont (StrictWriter.WriterT w m) where
     callCC = StrictWriter.liftCallCC callCC
+
+-- | @since 2.3
+instance (Monoid w, MonadCont m) => MonadCont (CPSRWS.RWST r w s m) where
+    callCC = CPSRWS.liftCallCC' callCC
+
+-- | @since 2.3
+instance (Monoid w, MonadCont m) => MonadCont (CPSWriter.WriterT w m) where
+    callCC = CPSWriter.liftCallCC callCC
+
+-- | @since 2.3
+instance
+  ( Monoid w
+  , MonadCont m
+  ) => MonadCont (AccumT w m) where
+    callCC = Accum.liftCallCC callCC
+
+-- | Introduces a recursive binding to the continuation.
+-- Due to the use of @callCC@, calling the continuation will interrupt execution
+-- of the current block creating an effect similar to goto/setjmp in C.
+--
+-- @since 2.3.1
+--
+label :: MonadCont m  => a -> m (a -> m b, a)
+label a = callCC $ \k -> let go b = k (go, b) in return (go, a)
+
+-- | Simplified version of `label` without arguments.
+-- 
+-- @since 2.3.1
+--
+label_ :: MonadCont m => m (m a)
+label_ = callCC $ return . fix
+
+-- | Lift a 'ContT.callCC'-style function through any 'MonadTrans'. 
+--
+-- = Note
+--
+-- For any function @f@, @'liftCallCC' f@ satisfies the [uniformity
+-- condition](https://hackage.haskell.org/package/transformers-0.5.6.2/docs/Control-Monad-Signatures.html#t:CallCC)
+-- provided that @f@ is quasi-algebraic. More specifically, for any @g@, we must have:
+--
+-- @
+-- 'join' '$' f (\\exit -> 'pure' '$' g (exit '.' 'pure') = f g
+-- @
+--
+-- 'ContT.callCC' is quasi-algebraic; furthermore, for any quasi-algebraic @f@,
+-- @'liftCallCC' f@ is also quasi-algebraic. 
+--
+-- = See also
+--
+-- * [Proof of quasi-algebraic
+-- properties](https://gist.github.com/KingoftheHomeless/5927257cc7f6f8a2da685a2045dac204)
+-- * [Original issue](https://github.com/haskell/mtl/issues/77)
+--
+-- @since 2.3.1
+liftCallCC :: 
+  forall (t :: (Type -> Type) -> Type -> Type) (m :: Type -> Type) (a :: Type) (b :: Type) . 
+  (MonadTrans t, Monad m
+#if !MIN_VERSION_transformers(0,6,0) || defined(__MHS__)
+  , forall (m' :: Type -> Type) . Monad m' => Monad (t m')
+#endif
+  ) =>
+  CallCC m (t m a) b -> CallCC (t m) a b
+liftCallCC f g = join . lift . f $ \exit -> pure $ g (lift . exit . pure)
diff --git a/Control/Monad/Error.hs b/Control/Monad/Error.hs
deleted file mode 100644
--- a/Control/Monad/Error.hs
+++ /dev/null
@@ -1,151 +0,0 @@
-{-# LANGUAGE CPP #-}
-{- |
-Module      :  Control.Monad.Error
-Copyright   :  (c) Michael Weber <michael.weber@post.rwth-aachen.de> 2001,
-               (c) Jeff Newbern 2003-2006,
-               (c) Andriy Palamarchuk 2006
-License     :  BSD-style (see the file LICENSE)
-
-Maintainer  :  libraries@haskell.org
-Stability   :  experimental
-Portability :  non-portable (multi-parameter type classes)
-
-[Computation type:] Computations which may fail or throw exceptions.
-
-[Binding strategy:] Failure records information about the cause\/location
-of the failure. Failure values bypass the bound function,
-other values are used as inputs to the bound function.
-
-[Useful for:] Building computations from sequences of functions that may fail
-or using exception handling to structure error handling.
-
-[Zero and plus:] Zero is represented by an empty error and the plus operation
-executes its second argument if the first fails.
-
-[Example type:] @'Either' String a@
-
-The Error monad (also called the Exception monad).
--}
-
-{-
-  Rendered by Michael Weber <mailto:michael.weber@post.rwth-aachen.de>,
-  inspired by the Haskell Monad Template Library from
-    Andy Gill (<http://web.cecs.pdx.edu/~andy/>)
--}
-module Control.Monad.Error
-  {-# DEPRECATED "Use \"Control.Monad.Except\" instead" #-} (
-    -- * Monads with error handling
-    MonadError(..),
-    Error(..),
-    -- * The ErrorT monad transformer
-    ErrorT(ErrorT),
-    runErrorT,
-    mapErrorT,
-    module Control.Monad,
-    module Control.Monad.Fix,
-    module Control.Monad.Trans,
-    -- * Example 1: Custom Error Data Type
-    -- $customErrorExample
-
-    -- * Example 2: Using ErrorT Monad Transformer
-    -- $ErrorTExample
-  ) where
-
-import Control.Monad.Error.Class
-import Control.Monad.Trans
-import Control.Monad.Trans.Error (ErrorT(ErrorT), runErrorT, mapErrorT)
-
-import Control.Monad
-import Control.Monad.Fix
-
-#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ < 707
-import Control.Monad.Instances ()
-#endif
-
-{- $customErrorExample
-Here is an example that demonstrates the use of a custom 'Error' data type with
-the 'throwError' and 'catchError' exception mechanism from 'MonadError'.
-The example throws an exception if the user enters an empty string
-or a string longer than 5 characters. Otherwise it prints length of the string.
-
->-- This is the type to represent length calculation error.
->data LengthError = EmptyString  -- Entered string was empty.
->          | StringTooLong Int   -- A string is longer than 5 characters.
->                                -- Records a length of the string.
->          | OtherError String   -- Other error, stores the problem description.
->
->-- We make LengthError an instance of the Error class
->-- to be able to throw it as an exception.
->instance Error LengthError where
->  noMsg    = OtherError "A String Error!"
->  strMsg s = OtherError s
->
->-- Converts LengthError to a readable message.
->instance Show LengthError where
->  show EmptyString = "The string was empty!"
->  show (StringTooLong len) =
->      "The length of the string (" ++ (show len) ++ ") is bigger than 5!"
->  show (OtherError msg) = msg
->
->-- For our monad type constructor, we use Either LengthError
->-- which represents failure using Left LengthError
->-- or a successful result of type a using Right a.
->type LengthMonad = Either LengthError
->
->main = do
->  putStrLn "Please enter a string:"
->  s <- getLine
->  reportResult (calculateLength s)
->
->-- Wraps length calculation to catch the errors.
->-- Returns either length of the string or an error.
->calculateLength :: String -> LengthMonad Int
->calculateLength s = (calculateLengthOrFail s) `catchError` Left
->
->-- Attempts to calculate length and throws an error if the provided string is
->-- empty or longer than 5 characters.
->-- The processing is done in Either monad.
->calculateLengthOrFail :: String -> LengthMonad Int
->calculateLengthOrFail [] = throwError EmptyString
->calculateLengthOrFail s | len > 5 = throwError (StringTooLong len)
->                        | otherwise = return len
->  where len = length s
->
->-- Prints result of the string length calculation.
->reportResult :: LengthMonad Int -> IO ()
->reportResult (Right len) = putStrLn ("The length of the string is " ++ (show len))
->reportResult (Left e) = putStrLn ("Length calculation failed with error: " ++ (show e))
--}
-
-{- $ErrorTExample
-@'ErrorT'@ monad transformer can be used to add error handling to another monad.
-Here is an example how to combine it with an @IO@ monad:
-
->import Control.Monad.Error
->
->-- An IO monad which can return String failure.
->-- It is convenient to define the monad type of the combined monad,
->-- especially if we combine more monad transformers.
->type LengthMonad = ErrorT String IO
->
->main = do
->  -- runErrorT removes the ErrorT wrapper
->  r <- runErrorT calculateLength
->  reportResult r
->
->-- Asks user for a non-empty string and returns its length.
->-- Throws an error if user enters an empty string.
->calculateLength :: LengthMonad Int
->calculateLength = do
->  -- all the IO operations have to be lifted to the IO monad in the monad stack
->  liftIO $ putStrLn "Please enter a non-empty string: "
->  s <- liftIO getLine
->  if null s
->    then throwError "The string was empty!"
->    else return $ length s
->
->-- Prints result of the string length calculation.
->reportResult :: Either String Int -> IO ()
->reportResult (Right len) = putStrLn ("The length of the string is " ++ (show len))
->reportResult (Left e) = putStrLn ("Length calculation failed with error: " ++ (show e))
--}
diff --git a/Control/Monad/Error/Class.hs b/Control/Monad/Error/Class.hs
--- a/Control/Monad/Error/Class.hs
+++ b/Control/Monad/Error/Class.hs
@@ -1,8 +1,12 @@
-{-# LANGUAGE CPP #-}
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE FunctionalDependencies #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE UndecidableInstances #-}
+{-# LANGUAGE Safe #-}
+-- Needed because the CPSed versions of Writer and State are secretly State
+-- wrappers, which don't force such constraints, even though they should legally
+-- be there.
+{-# OPTIONS_GHC -Wno-redundant-constraints #-}
 
 {- |
 Module      :  Control.Monad.Error.Class
@@ -39,36 +43,40 @@
     Andy Gill (<http://web.cecs.pdx.edu/~andy/>)
 -}
 module Control.Monad.Error.Class (
-    Error(..),
     MonadError(..),
     liftEither,
+    tryError,
+    withError,
+    handleError,
+    onError,
+    mapError,
+    modifyError,
   ) where
 
-import Control.Monad.Trans.Except (Except, ExceptT)
-import Control.Monad.Trans.Error (Error(..), ErrorT)
-import qualified Control.Monad.Trans.Except as ExceptT (throwE, catchE)
-import qualified Control.Monad.Trans.Error as ErrorT (throwError, catchError)
-import Control.Monad.Trans.Identity as Identity
-import Control.Monad.Trans.List as List
-import Control.Monad.Trans.Maybe as Maybe
-import Control.Monad.Trans.Reader as Reader
-import Control.Monad.Trans.RWS.Lazy as LazyRWS
-import Control.Monad.Trans.RWS.Strict as StrictRWS
-import Control.Monad.Trans.State.Lazy as LazyState
-import Control.Monad.Trans.State.Strict as StrictState
-import Control.Monad.Trans.Writer.Lazy as LazyWriter
-import Control.Monad.Trans.Writer.Strict as StrictWriter
-
+import Control.Monad.Trans.Except (ExceptT)
+import qualified Control.Monad.Trans.Except as ExceptT (catchE, runExceptT, throwE)
+import Control.Monad.Trans.Identity (IdentityT)
+import qualified Control.Monad.Trans.Identity as Identity
+import Control.Monad.Trans.Maybe (MaybeT)
+import qualified Control.Monad.Trans.Maybe as Maybe
+import Control.Monad.Trans.Reader (ReaderT)
+import qualified Control.Monad.Trans.Reader as Reader
+import qualified Control.Monad.Trans.RWS.Lazy as LazyRWS
+import qualified Control.Monad.Trans.RWS.Strict as StrictRWS
+import qualified Control.Monad.Trans.State.Lazy as LazyState
+import qualified Control.Monad.Trans.State.Strict as StrictState
+import qualified Control.Monad.Trans.Writer.Lazy as LazyWriter
+import qualified Control.Monad.Trans.Writer.Strict as StrictWriter
+import Control.Monad.Trans.Accum (AccumT)
+import qualified Control.Monad.Trans.Accum as Accum
+import qualified Control.Monad.Trans.RWS.CPS as CPSRWS
+import qualified Control.Monad.Trans.Writer.CPS as CPSWriter
 import Control.Monad.Trans.Class (lift)
 import Control.Exception (IOException, catch, ioError)
-import Control.Monad
-
-#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ < 707
-import Control.Monad.Instances ()
-#endif
-
-import Data.Monoid
-import Prelude (Either(..), Maybe(..), either, (.), IO)
+import Control.Monad (Monad ((>>=), (>>)))
+import Data.Functor.Product (Product(..))
+import Data.Monoid (Monoid)
+import Prelude (Either (Left, Right), Maybe (Nothing), either, flip, (.), IO, pure, (<$>))
 
 {- |
 The strategy of combining computations that can throw exceptions
@@ -102,9 +110,7 @@
     Note that @handler@ and the do-block must have the same return type.
     -}
     catchError :: m a -> (e -> m a) -> m a
-#if __GLASGOW_HASKELL__ >= 707
     {-# MINIMAL throwError, catchError #-}
-#endif
 
 {- |
 Lifts an @'Either' e@ into any @'MonadError' e@.
@@ -116,7 +122,7 @@
 @since 2.2.2
 -}
 liftEither :: MonadError e m => Either e a -> m a
-liftEither = either throwError return
+liftEither = either throwError pure
 
 instance MonadError IOException IO where
     throwError = ioError
@@ -136,10 +142,6 @@
     Left  l `catchError` h = h l
     Right r `catchError` _ = Right r
 
-instance (Monad m, Error e) => MonadError e (ErrorT e m) where
-    throwError = ErrorT.throwError
-    catchError = ErrorT.catchError
-
 {- | @since 2.2 -}
 instance Monad m => MonadError e (ExceptT e m) where
     throwError = ExceptT.throwE
@@ -155,10 +157,6 @@
     throwError = lift . throwError
     catchError = Identity.liftCatch catchError
 
-instance MonadError e m => MonadError e (ListT m) where
-    throwError = lift . throwError
-    catchError = List.liftCatch catchError
-
 instance MonadError e m => MonadError e (MaybeT m) where
     throwError = lift . throwError
     catchError = Maybe.liftCatch catchError
@@ -190,3 +188,108 @@
 instance (Monoid w, MonadError e m) => MonadError e (StrictWriter.WriterT w m) where
     throwError = lift . throwError
     catchError = StrictWriter.liftCatch catchError
+
+-- | @since 2.3
+instance (Monoid w, MonadError e m) => MonadError e (CPSRWS.RWST r w s m) where
+    throwError = lift . throwError
+    catchError = CPSRWS.liftCatch catchError
+
+-- | @since 2.3
+instance (Monoid w, MonadError e m) => MonadError e (CPSWriter.WriterT w m) where
+    throwError = lift . throwError
+    catchError = CPSWriter.liftCatch catchError
+
+-- | @since 2.3
+instance
+  ( Monoid w
+  , MonadError e m
+  ) => MonadError e (AccumT w m) where
+    throwError = lift . throwError
+    catchError = Accum.liftCatch catchError
+
+-- | @since 2.3.2
+instance (MonadError e m, MonadError e n) => MonadError e (Product m n) where
+    throwError e = Pair (throwError e) (throwError e)
+    catchError (Pair ma na) f = Pair (catchError ma (productFst . f)) (catchError na (productSnd . f))
+        where
+            productFst (Pair a _) = a
+            productSnd (Pair _ b) = b
+
+-- | 'MonadError' analogue to the 'Control.Exception.try' function.
+--
+-- @since 2.3
+tryError :: MonadError e m => m a -> m (Either e a)
+tryError action = (Right <$> action) `catchError` (pure . Left)
+
+-- | 'MonadError' analogue to the 'withExceptT' function.
+-- Modify the value (but not the type) of an error.  The type is
+-- fixed because of the functional dependency @m -> e@.  If you need
+-- to change the type of @e@ use 'mapError' or 'modifyError'.
+--
+-- @since 2.3
+withError :: MonadError e m => (e -> e) -> m a -> m a
+withError f = handleError (throwError . f)
+
+-- | As 'handle' is flipped 'Control.Exception.catch', 'handleError'
+-- is flipped 'catchError'.
+--
+-- @since 2.3
+handleError :: MonadError e m => (e -> m a) -> m a -> m a
+handleError = flip catchError
+
+-- | If an action throws an error, run a second action and rethrow the error.
+-- If the second action also throws an error, it takes precedence.  Do not run
+-- the second action at all if the first succeeds.
+--
+-- @since 2.3.2
+onError :: MonadError e m => m a -> m b -> m a
+onError action1 action2 = action1 `catchError` \e -> action2 >> throwError e
+
+-- | 'MonadError' analogue of the 'mapExceptT' function.  The
+-- computation is unwrapped, a function is applied to the @Either@, and
+-- the result is lifted into the second 'MonadError' instance.
+--
+-- @since 2.3
+mapError :: (MonadError e m, MonadError e' n) => (m (Either e a) -> n (Either e' b)) -> m a -> n b
+mapError f action = f (tryError action) >>= liftEither
+
+{- |
+A different 'MonadError' analogue to the 'withExceptT' function.
+Modify the value (and possibly the type) of an error in an @ExceptT@-transformed
+monad, while stripping the @ExceptT@ layer.
+
+This is useful for adapting the 'MonadError' constraint of a computation.
+
+For example:
+
+> data DatabaseError = ...
+>
+> performDatabaseQuery :: (MonadError DatabaseError m, ...) => m PersistedValue
+>
+> data AppError
+>   = MkDatabaseError DatabaseError
+>   | ...
+>
+> app :: (MonadError AppError m, ...) => m ()
+
+Given these types, @performDatabaseQuery@ cannot be used directly inside
+@app@, because the error types don't match. Using 'modifyError', an equivalent
+function with a different error type can be constructed:
+
+> performDatabaseQuery' :: (MonadError AppError m, ...) => m PersistedValue
+> performDatabaseQuery' = modifyError MkDatabaseError performDatabaseQuery
+
+Since the error types do match, @performDatabaseQuery'@ _can_ be used in @app@,
+assuming all other constraints carry over.
+
+This works by instantiating the @m@ in the type of @performDatabaseQuery@ to
+@ExceptT DatabaseError m'@, which satisfies the @MonadError DatabaseError@
+constraint. Immediately, the @ExceptT DatabaseError@ layer is unwrapped,
+producing 'Either' a @DatabaseError@ or a @PersistedValue@. If it's the former,
+the error is wrapped in @MkDatabaseError@ and re-thrown in the inner monad,
+otherwise the result value is returned.
+
+@since 2.3.1
+-}
+modifyError :: MonadError e' m => (e -> e') -> ExceptT e m a -> m a
+modifyError f m = ExceptT.runExceptT m >>= either (throwError . f) pure
diff --git a/Control/Monad/Except.hs b/Control/Monad/Except.hs
--- a/Control/Monad/Except.hs
+++ b/Control/Monad/Except.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE CPP #-}
+{-# LANGUAGE Safe #-}
 {- |
 Module      :  Control.Monad.Except
 Copyright   :  (c) Michael Weber <michael.weber@post.rwth-aachen.de> 2001,
@@ -36,22 +36,23 @@
     -- * Warning
     -- $warning
     -- * Monads with error handling
-    MonadError(..),
-    liftEither,
+    Error.MonadError(..),
+    Error.liftEither,
+    Error.tryError,
+    Error.withError,
+    Error.handleError,
+    Error.onError,
+    Error.mapError,
+    Error.modifyError,
     -- * The ExceptT monad transformer
-    ExceptT(ExceptT),
-    Except,
-
-    runExceptT,
-    mapExceptT,
-    withExceptT,
-    runExcept,
-    mapExcept,
-    withExcept,
-
-    module Control.Monad,
-    module Control.Monad.Fix,
-    module Control.Monad.Trans,
+    Except.ExceptT(ExceptT),
+    Except.Except,
+    Except.runExceptT,
+    Except.mapExceptT,
+    Except.withExceptT,
+    Except.runExcept,
+    Except.mapExcept,
+    Except.withExcept,
     -- * Example 1: Custom Error Data Type
     -- $customErrorExample
 
@@ -59,21 +60,8 @@
     -- $ExceptTExample
   ) where
 
-import Control.Monad.Error.Class
-import Control.Monad.Trans
-import Control.Monad.Trans.Except
-  ( ExceptT(ExceptT), Except, except
-  , runExcept, runExceptT
-  , mapExcept, mapExceptT
-  , withExcept, withExceptT
-  )
-
-import Control.Monad
-import Control.Monad.Fix
-
-#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ < 707
-import Control.Monad.Instances ()
-#endif
+import qualified Control.Monad.Error.Class as Error
+import qualified Control.Monad.Trans.Except as Except
 
 {- $warning
 Please do not confuse 'ExceptT' and 'throwError' with 'Control.Exception.Exception' /
diff --git a/Control/Monad/Identity.hs b/Control/Monad/Identity.hs
--- a/Control/Monad/Identity.hs
+++ b/Control/Monad/Identity.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE Safe #-}
 {- |
 Module      :  Control.Monad.Identity
 Copyright   :  (c) Andy Gill 2001,
@@ -35,13 +36,7 @@
 module Control.Monad.Identity (
     module Data.Functor.Identity,
     module Control.Monad.Trans.Identity,
-
-    module Control.Monad,
-    module Control.Monad.Fix,
    ) where
 
 import Data.Functor.Identity
 import Control.Monad.Trans.Identity
-
-import Control.Monad
-import Control.Monad.Fix
diff --git a/Control/Monad/List.hs b/Control/Monad/List.hs
deleted file mode 100644
--- a/Control/Monad/List.hs
+++ /dev/null
@@ -1,25 +0,0 @@
------------------------------------------------------------------------------
--- |
--- Module      :  Control.Monad.List
--- Copyright   :  (c) Andy Gill 2001,
---                (c) Oregon Graduate Institute of Science and Technology, 2001
--- License     :  BSD-style (see the file LICENSE)
---
--- Maintainer  :  libraries@haskell.org
--- Stability   :  experimental
--- Portability :  portable
---
--- The List monad.
---
------------------------------------------------------------------------------
-
-module Control.Monad.List (
-    ListT(..),
-    mapListT,
-    module Control.Monad,
-    module Control.Monad.Trans,
-  ) where
-
-import Control.Monad
-import Control.Monad.Trans
-import Control.Monad.Trans.List
diff --git a/Control/Monad/RWS.hs b/Control/Monad/RWS.hs
--- a/Control/Monad/RWS.hs
+++ b/Control/Monad/RWS.hs
@@ -1,3 +1,5 @@
+{-# LANGUAGE Safe #-}
+
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Control.Monad.RWS
diff --git a/Control/Monad/RWS/CPS.hs b/Control/Monad/RWS/CPS.hs
new file mode 100644
--- /dev/null
+++ b/Control/Monad/RWS/CPS.hs
@@ -0,0 +1,50 @@
+{-# LANGUAGE Safe #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Control.Monad.RWS.Strict
+-- Copyright   :  (c) Andy Gill 2001,
+--                (c) Oregon Graduate Institute of Science and Technology, 2001
+-- License     :  BSD-style (see the file LICENSE)
+--
+-- Maintainer  :  libraries@haskell.org
+-- Stability   :  experimental
+-- Portability :  non-portable (multi-param classes, functional dependencies)
+--
+-- Strict RWS monad that uses continuation-passing-style to achieve constant
+-- space usage.
+--
+--      Inspired by the paper
+--      /Functional Programming with Overloading and Higher-Order Polymorphism/,
+--        Mark P Jones (<http://web.cecs.pdx.edu/~mpj/>)
+--          Advanced School of Functional Programming, 1995.
+--
+-- /Since: mtl-2.3, transformers-0.5.6/
+-----------------------------------------------------------------------------
+
+module Control.Monad.RWS.CPS (
+    -- * The RWS monad
+    RWS,
+    rws,
+    runRWS,
+    evalRWS,
+    execRWS,
+    mapRWS,
+    withRWS,
+    -- * The RWST monad transformer
+    RWST,
+    runRWST,
+    evalRWST,
+    execRWST,
+    mapRWST,
+    withRWST,
+    -- * Strict Reader-writer-state monads
+    module Control.Monad.RWS.Class,
+    module Control.Monad.Trans,
+  ) where
+
+import Control.Monad.RWS.Class
+
+import Control.Monad.Trans
+import Control.Monad.Trans.RWS.CPS (
+    RWS, rws, runRWS, evalRWS, execRWS, mapRWS, withRWS,
+    RWST, runRWST, evalRWST, execRWST, mapRWST, withRWST)
diff --git a/Control/Monad/RWS/Class.hs b/Control/Monad/RWS/Class.hs
--- a/Control/Monad/RWS/Class.hs
+++ b/Control/Monad/RWS/Class.hs
@@ -1,8 +1,9 @@
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE FunctionalDependencies #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
-{-# LANGUAGE UndecidableInstances #-}
 -- Search for UndecidableInstances to see why this is needed
+{-# LANGUAGE UndecidableInstances #-}
+{-# LANGUAGE Safe #-}
 
 -----------------------------------------------------------------------------
 -- |
@@ -34,23 +35,24 @@
 import Control.Monad.State.Class
 import Control.Monad.Writer.Class
 
-import Control.Monad.Trans.Class
-import Control.Monad.Trans.Error(Error, ErrorT)
-import Control.Monad.Trans.Except(ExceptT)
-import Control.Monad.Trans.Maybe(MaybeT)
-import Control.Monad.Trans.Identity(IdentityT)
-import Control.Monad.Trans.RWS.Lazy as Lazy (RWST)
+import Control.Monad.Trans.Except (ExceptT)
+import Control.Monad.Trans.Maybe (MaybeT)
+import Control.Monad.Trans.Identity (IdentityT)
+import qualified Control.Monad.Trans.RWS.CPS as CPS (RWST)
+import qualified Control.Monad.Trans.RWS.Lazy as Lazy (RWST)
 import qualified Control.Monad.Trans.RWS.Strict as Strict (RWST)
-
-import Data.Monoid
+import Data.Functor.Product (Product(..))
 
 class (Monoid w, MonadReader r m, MonadWriter w m, MonadState s m)
    => MonadRWS r w s m | m -> r, m -> w, m -> s
 
+-- | @since 2.3
+instance (Monoid w, Monad m) => MonadRWS r w s (CPS.RWST r w s m)
+
 instance (Monoid w, Monad m) => MonadRWS r w s (Lazy.RWST r w s m)
 
 instance (Monoid w, Monad m) => MonadRWS r w s (Strict.RWST r w s m)
- 
+
 ---------------------------------------------------------------------------
 -- Instances for other mtl transformers
 --
@@ -59,6 +61,8 @@
 
 -- | @since 2.2
 instance MonadRWS r w s m => MonadRWS r w s (ExceptT e m)
-instance (Error e, MonadRWS r w s m) => MonadRWS r w s (ErrorT e m)
 instance MonadRWS r w s m => MonadRWS r w s (IdentityT m)
 instance MonadRWS r w s m => MonadRWS r w s (MaybeT m)
+
+-- | @since 2.3.2
+instance (MonadRWS r w s m, MonadRWS r w s n) => MonadRWS r w s (Product m n)
diff --git a/Control/Monad/RWS/Lazy.hs b/Control/Monad/RWS/Lazy.hs
--- a/Control/Monad/RWS/Lazy.hs
+++ b/Control/Monad/RWS/Lazy.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE Safe #-}
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Control.Monad.RWS.Lazy
@@ -35,10 +36,7 @@
     withRWST,
     -- * Lazy Reader-writer-state monads
     module Control.Monad.RWS.Class,
-    module Control.Monad,
-    module Control.Monad.Fix,
     module Control.Monad.Trans,
-    module Data.Monoid,
   ) where
 
 import Control.Monad.RWS.Class
@@ -47,7 +45,3 @@
 import Control.Monad.Trans.RWS.Lazy (
     RWS, rws, runRWS, evalRWS, execRWS, mapRWS, withRWS,
     RWST(RWST), runRWST, evalRWST, execRWST, mapRWST, withRWST)
-
-import Control.Monad
-import Control.Monad.Fix
-import Data.Monoid
diff --git a/Control/Monad/RWS/Strict.hs b/Control/Monad/RWS/Strict.hs
--- a/Control/Monad/RWS/Strict.hs
+++ b/Control/Monad/RWS/Strict.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE Safe #-}
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Control.Monad.RWS.Strict
@@ -35,19 +36,12 @@
     withRWST,
     -- * Strict Reader-writer-state monads
     module Control.Monad.RWS.Class,
-    module Control.Monad,
-    module Control.Monad.Fix,
     module Control.Monad.Trans,
-    module Data.Monoid,
   ) where
 
 import Control.Monad.RWS.Class
-
 import Control.Monad.Trans
+
 import Control.Monad.Trans.RWS.Strict (
     RWS, rws, runRWS, evalRWS, execRWS, mapRWS, withRWS,
     RWST(RWST), runRWST, evalRWST, execRWST, mapRWST, withRWST)
-
-import Control.Monad
-import Control.Monad.Fix
-import Data.Monoid
diff --git a/Control/Monad/Reader.hs b/Control/Monad/Reader.hs
--- a/Control/Monad/Reader.hs
+++ b/Control/Monad/Reader.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE Safe #-}
 {- |
 Module      :  Control.Monad.Reader
 Copyright   :  (c) Andy Gill 2001,
@@ -37,8 +38,8 @@
 
 module Control.Monad.Reader (
     -- * MonadReader class
-    MonadReader(..),
-    asks,
+    MonadReader.MonadReader(..),
+    MonadReader.asks,
     -- * The Reader monad
     Reader,
     runReader,
@@ -49,8 +50,6 @@
     runReaderT,
     mapReaderT,
     withReaderT,
-    module Control.Monad,
-    module Control.Monad.Fix,
     module Control.Monad.Trans,
     -- * Example 1: Simple Reader Usage
     -- $simpleReaderExample
@@ -62,16 +61,13 @@
     -- $ReaderTExample
     ) where
 
-import Control.Monad.Reader.Class
+import qualified Control.Monad.Reader.Class as MonadReader
+import Control.Monad.Trans
 
 import Control.Monad.Trans.Reader (
     Reader, runReader, mapReader, withReader,
     ReaderT(ReaderT), runReaderT, mapReaderT, withReaderT)
-import Control.Monad.Trans
 
-import Control.Monad
-import Control.Monad.Fix
-
 {- $simpleReaderExample
 
 In this example the @Reader@ monad provides access to variable bindings.
@@ -80,8 +76,12 @@
 You can see how to run a Reader monad and retrieve data from it
 with 'runReader', how to access the Reader data with 'ask' and 'asks'.
 
-> type Bindings = Map String Int;
+>import           Control.Monad.Reader
+>import           Data.Map (Map)
+>import qualified Data.Map as Map
 >
+>type Bindings = Map String Int
+>
 >-- Returns True if the "count" variable contains correct bindings size.
 >isCountCorrect :: Bindings -> Bool
 >isCountCorrect bindings = runReader calc_isCountCorrect bindings
@@ -93,22 +93,26 @@
 >    bindings <- ask
 >    return (count == (Map.size bindings))
 >
->-- The selector function to  use with 'asks'.
+>-- The selector function to use with 'asks'.
 >-- Returns value of the variable with specified name.
 >lookupVar :: String -> Bindings -> Int
 >lookupVar name bindings = maybe 0 id (Map.lookup name bindings)
 >
->sampleBindings = Map.fromList [("count",3), ("1",1), ("b",2)]
+>sampleBindings :: Bindings
+>sampleBindings = Map.fromList [("count", 3), ("1", 1), ("b", 2)]
 >
+>main :: IO ()
 >main = do
->    putStr $ "Count is correct for bindings " ++ (show sampleBindings) ++ ": ";
->    putStrLn $ show (isCountCorrect sampleBindings);
+>    putStr $ "Count is correct for bindings " ++ (show sampleBindings) ++ ": "
+>    putStrLn $ show (isCountCorrect sampleBindings)
 -}
 
 {- $localExample
 
 Shows how to modify Reader content with 'local'.
 
+>import Control.Monad.Reader
+>
 >calculateContentLen :: Reader String Int
 >calculateContentLen = do
 >    content <- ask
@@ -118,6 +122,7 @@
 >calculateModifiedContentLen :: Reader String Int
 >calculateModifiedContentLen = local ("Prefix " ++) calculateContentLen
 >
+>main :: IO ()
 >main = do
 >    let s = "12345";
 >    let modifiedLen = runReader calculateModifiedContentLen s
@@ -133,12 +138,14 @@
 This can be easily done with the 'ReaderT' monad transformer.
 This example shows how to combine @ReaderT@ with the IO monad.
 
+>import Control.Monad.Reader
+>
 >-- The Reader/IO combined monad, where Reader stores a string.
 >printReaderContent :: ReaderT String IO ()
 >printReaderContent = do
 >    content <- ask
 >    liftIO $ putStrLn ("The Reader Content: " ++ content)
 >
->main = do
->    runReaderT printReaderContent "Some Content"
+>main :: IO ()
+>main = runReaderT printReaderContent "Some Content"
 -}
diff --git a/Control/Monad/Reader/Class.hs b/Control/Monad/Reader/Class.hs
--- a/Control/Monad/Reader/Class.hs
+++ b/Control/Monad/Reader/Class.hs
@@ -1,9 +1,13 @@
-{-# LANGUAGE CPP #-}
+{-# LANGUAGE Safe #-}
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE FunctionalDependencies #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
-{-# LANGUAGE UndecidableInstances #-}
 -- Search for UndecidableInstances to see why this is needed
+{-# LANGUAGE UndecidableInstances #-}
+-- Needed because the CPSed versions of Writer and State are secretly State
+-- wrappers, which don't force such constraints, even though they should legally
+-- be there.
+{-# OPTIONS_GHC -Wno-redundant-constraints #-}
 {- |
 Module      :  Control.Monad.Reader.Class
 Copyright   :  (c) Andy Gill 2001,
@@ -46,24 +50,26 @@
     asks,
     ) where
 
-import Control.Monad.Trans.Cont as Cont
-import Control.Monad.Trans.Except
-import Control.Monad.Trans.Error
-import Control.Monad.Trans.Identity
-import Control.Monad.Trans.List
-import Control.Monad.Trans.Maybe
+import qualified Control.Monad.Trans.Cont as Cont
+import Control.Monad.Trans.Cont (ContT)
+import Control.Monad.Trans.Except (ExceptT, mapExceptT)
+import Control.Monad.Trans.Identity (IdentityT, mapIdentityT)
+import Control.Monad.Trans.Maybe (MaybeT, mapMaybeT)
 import Control.Monad.Trans.Reader (ReaderT)
-import qualified Control.Monad.Trans.Reader as ReaderT (ask, local, reader)
-import qualified Control.Monad.Trans.RWS.Lazy as LazyRWS (RWST, ask, local, reader)
-import qualified Control.Monad.Trans.RWS.Strict as StrictRWS (RWST, ask, local, reader)
-import Control.Monad.Trans.State.Lazy as Lazy
-import Control.Monad.Trans.State.Strict as Strict
-import Control.Monad.Trans.Writer.Lazy as Lazy
-import Control.Monad.Trans.Writer.Strict as Strict
-
+import qualified Control.Monad.Trans.Reader as ReaderT
+import qualified Control.Monad.Trans.RWS.Lazy as LazyRWS
+import qualified Control.Monad.Trans.RWS.Strict as StrictRWS
+import qualified Control.Monad.Trans.State.Lazy as Lazy
+import qualified Control.Monad.Trans.State.Strict as Strict
+import qualified Control.Monad.Trans.Writer.Lazy as Lazy
+import qualified Control.Monad.Trans.Writer.Strict as Strict
+import Control.Monad.Trans.Accum (AccumT)
+import qualified Control.Monad.Trans.Accum as Accum
+import Control.Monad.Trans.Select (SelectT (SelectT), runSelectT)
+import qualified Control.Monad.Trans.RWS.CPS as CPSRWS
+import qualified Control.Monad.Trans.Writer.CPS as CPS
 import Control.Monad.Trans.Class (lift)
-import Control.Monad
-import Data.Monoid
+import Data.Functor.Product (Product(..))
 
 -- ----------------------------------------------------------------------------
 -- class MonadReader
@@ -73,9 +79,7 @@
 -- Note, the partially applied function type @(->) r@ is a simple reader monad.
 -- See the @instance@ declaration below.
 class Monad m => MonadReader r m | m -> r where
-#if __GLASGOW_HASKELL__ >= 707
     {-# MINIMAL (ask | reader), local #-}
-#endif
     -- | Retrieves the monad environment.
     ask   :: m r
     ask = reader id
@@ -111,6 +115,12 @@
     local = ReaderT.local
     reader = ReaderT.reader
 
+-- | @since 2.3
+instance (Monad m, Monoid w) => MonadReader r (CPSRWS.RWST r w s m) where
+    ask = CPSRWS.ask
+    local = CPSRWS.local
+    reader = CPSRWS.reader
+
 instance (Monad m, Monoid w) => MonadReader r (LazyRWS.RWST r w s m) where
     ask = LazyRWS.ask
     local = LazyRWS.local
@@ -132,11 +142,6 @@
     local = Cont.liftLocal ask local
     reader = lift . reader
 
-instance (Error e, MonadReader r m) => MonadReader r (ErrorT e m) where
-    ask   = lift ask
-    local = mapErrorT . local
-    reader = lift . reader
-
 {- | @since 2.2 -}
 instance MonadReader r m => MonadReader r (ExceptT e m) where
     ask   = lift ask
@@ -148,11 +153,6 @@
     local = mapIdentityT . local
     reader = lift . reader
 
-instance MonadReader r m => MonadReader r (ListT m) where
-    ask   = lift ask
-    local = mapListT . local
-    reader = lift . reader
-
 instance MonadReader r m => MonadReader r (MaybeT m) where
     ask   = lift ask
     local = mapMaybeT . local
@@ -168,6 +168,12 @@
     local = Strict.mapStateT . local
     reader = lift . reader
 
+-- | @since 2.3
+instance (Monoid w, MonadReader r m) => MonadReader r (CPS.WriterT w m) where
+    ask   = lift ask
+    local = CPS.mapWriterT . local
+    reader = lift . reader
+
 instance (Monoid w, MonadReader r m) => MonadReader r (Lazy.WriterT w m) where
     ask   = lift ask
     local = Lazy.mapWriterT . local
@@ -177,3 +183,28 @@
     ask   = lift ask
     local = Strict.mapWriterT . local
     reader = lift . reader
+
+-- | @since 2.3
+instance
+  ( Monoid w
+  , MonadReader r m
+  ) => MonadReader r (AccumT w m) where
+    ask = lift ask
+    local = Accum.mapAccumT . local
+    reader = lift . reader
+
+-- | @since 2.3
+instance
+  ( MonadReader r' m
+  ) => MonadReader r' (SelectT r m) where
+    ask = lift ask
+    -- there is no Select.liftLocal
+    local f m = SelectT $ \c -> do
+      r <- ask
+      local f (runSelectT m (local (const r) . c))
+    reader = lift . reader
+
+-- | @since 2.3.2
+instance (MonadReader r m, MonadReader r n) => MonadReader r (Product m n) where
+    ask = Pair ask ask
+    local f (Pair ma na) = Pair (local f ma) (local f na)
diff --git a/Control/Monad/Select.hs b/Control/Monad/Select.hs
new file mode 100644
--- /dev/null
+++ b/Control/Monad/Select.hs
@@ -0,0 +1,316 @@
+{-# LANGUAGE DerivingVia #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE FunctionalDependencies #-}
+{-# LANGUAGE KindSignatures #-}
+{-# LANGUAGE StandaloneDeriving #-}
+{-# LANGUAGE Trustworthy #-}
+{-# LANGUAGE UndecidableInstances #-}
+-- Later GHCs infer DerivingVia as not Safe
+-- We just downgrade to Trustworthy and go fish
+{-# OPTIONS_GHC -Wno-trustworthy-safe #-}
+
+-- | Module: Control.Monad.Select
+-- Copyright: (C) Koz Ross 2022
+-- License: BSD-3-Clause (see the LICENSE file)
+-- Maintainer: koz.ross@retro-freedom.nz
+-- Stability: Experimental
+-- Portability: GHC only
+--
+-- [Computation type:] Backtracking search, with @r@ as a \'ranking\' or
+-- \'evaluation\' type.
+--
+-- [Binding strategy:] Binding a function to a monadic value \'chains together\'
+-- strategies; having seen the result of one search, decide which policy to use
+-- to continue.
+--
+-- [Useful for:] Search problems.
+--
+-- [Zero and plus:] None.
+--
+-- [Example type:] @'Control.Monad.Trans.Select.Select' r a@
+--
+-- = A note on commutativity
+--
+-- Some effects are /commutative/: it doesn't matter which you resolve first, as
+-- all possible orderings of commutative effects are isomorphic. Consider, for
+-- example, the reader and state effects, as exemplified by 'ReaderT' and
+-- 'StrictState.StateT' respectively. If we have
+-- @'ReaderT' r ('StrictState.State' s) a@, this is
+-- effectively @r -> 'StrictState.State' s a ~ r -> s -> (a, s)@; if we instead have
+-- @'StrictState.StateT' s ('Control.Monad.Trans.Reader.Reader' r) a@, this is effectively
+-- @s -> 'Control.Monad.Trans.Reader' r (a, s) ~ s -> r -> (a, s)@. Since we
+-- can always reorder function arguments (for example, using 'flip', as in
+-- this case) without changing the result, these are
+-- isomorphic, showing that reader and state are /commutative/, or, more
+-- precisely, /commute with each other/.
+--
+-- However, this isn't generally the case. Consider instead the error and state
+-- effects, as exemplified by 'MaybeT' and 'StrictState.StateT' respectively.
+-- If we have @'MaybeT' ('Control.Monad.Trans.State.Strict.State' s) a@, this
+-- is effectively @'State' s ('Maybe' a) ~ s -> ('Maybe' a, s)@: put simply,
+-- the error can occur only in the /result/, but
+-- not the state, which always \'survives\'. On the other hand, if we have
+-- @'StrictState.StateT' s 'Maybe' a@, this is instead @s -> 'Maybe' (a, s)@: here,
+-- if we error, we lose /both/ the state and the result! Thus, error and state effects
+-- do /not/ commute with each other.
+--
+-- As the MTL is capability-based, we support any ordering of non-commutative
+-- effects on an equal footing. Indeed, if you wish to use
+-- 'Control.Monad.State.Class.MonadState', for
+-- example, whether your final monadic stack ends up being @'MaybeT'
+-- ('Control.Monad.Trans.State.Strict.State' s)
+-- a@, @'StrictState.StateT' s 'Maybe' a@, or anything else, you will be able to write your
+-- desired code without having to consider such differences. However, the way we
+-- /implement/ these capabilities for any given transformer (or rather, any
+-- given transformed stack) /is/ affected by this ordering unless the effects in
+-- question are commutative.
+--
+-- We note in this module which effects the accumulation effect does and doesn't
+-- commute with; we also note on implementations with non-commutative
+-- transformers what the outcome will be. Note that, depending on how the
+-- \'inner monad\' is structured, this may be more complex than we note: we
+-- describe only what impact the \'outer effect\' has, not what else might be in
+-- the stack.
+--
+-- = Commutativity of selection
+--
+-- The selection effect commutes with the identity effect ('IdentityT'), but
+-- nothing else.
+module Control.Monad.Select
+  ( -- * Type class
+    MonadSelect (..),
+
+    -- * Lifting helper type
+    LiftingSelect (..),
+  )
+where
+
+import Control.Monad.Trans.Accum (AccumT)
+import Control.Monad.Trans.Class (MonadTrans (lift))
+import Control.Monad.Trans.Cont (ContT)
+import Control.Monad.Trans.Except (ExceptT)
+import Control.Monad.Trans.Identity (IdentityT)
+import Control.Monad.Trans.Maybe (MaybeT)
+import qualified Control.Monad.Trans.RWS.CPS as CPSRWS
+import qualified Control.Monad.Trans.RWS.Lazy as LazyRWS
+import qualified Control.Monad.Trans.RWS.Strict as StrictRWS
+import Control.Monad.Trans.Reader (ReaderT)
+import Control.Monad.Trans.Select (SelectT)
+import qualified Control.Monad.Trans.Select as Select
+import qualified Control.Monad.Trans.State.Lazy as LazyState
+import qualified Control.Monad.Trans.State.Strict as StrictState
+import qualified Control.Monad.Trans.Writer.CPS as CPSWriter
+import qualified Control.Monad.Trans.Writer.Lazy as LazyWriter
+import qualified Control.Monad.Trans.Writer.Strict as StrictWriter
+import Data.Functor.Identity (Identity)
+import Data.Kind (Type)
+
+-- | The capability to search with backtracking. Essentially describes a
+-- \'policy function\': given the state of the search (and a \'ranking\' or
+-- \'evaluation\' of each possible result so far), pick the result that's
+-- currently best.
+--
+-- = Laws
+--
+-- Any instance of 'MonadSelect' must follow these laws:
+--
+-- * @'select' ('const' x)@ @=@ @'pure' x@
+-- * @'select' f '*>' 'select' g@ @=@ @'select' g@
+--
+-- @since 2.3
+class (Monad m) => MonadSelect r m | m -> r where
+  select :: ((a -> r) -> a) -> m a
+
+-- | @since 2.3
+instance MonadSelect r (SelectT r Identity) where
+  select = Select.select
+
+-- | \'Extends\' the possibilities considered by @m@ to include 'Nothing'; this
+-- means that 'Nothing' gains a \'rank\' (namely, a value of @r@), and the
+-- potential result could also be 'Nothing'.
+--
+-- @since 2.3
+deriving via
+  (LiftingSelect MaybeT m)
+  instance
+    (MonadSelect r m) =>
+    MonadSelect r (MaybeT m)
+
+-- | The continuation describes a way of choosing a \'search\' or \'ranking\'
+-- strategy for @r@, based on a \'ranking\' using @r'@, given any @a@. We then
+-- get a \'search\' strategy for @r@.
+--
+-- @since 2.3
+deriving via
+  (LiftingSelect (ContT r) m)
+  instance
+    (MonadSelect r' m) =>
+    MonadSelect r' (ContT r m)
+
+-- | \'Extends\' the possibilities considered by @m@ to include every value of
+-- @e@; this means that the potential result could be either a 'Left' (making it
+-- a choice of type @e@) or a 'Right' (making it a choice of type @a@).
+--
+-- @since 2.3
+deriving via
+  (LiftingSelect (ExceptT e) m)
+  instance
+    (MonadSelect r m) =>
+    MonadSelect r (ExceptT e m)
+
+-- | @since 2.3
+deriving via
+  (LiftingSelect IdentityT m)
+  instance
+    (MonadSelect r m) =>
+    MonadSelect r (IdentityT m)
+
+-- | Provides a read-only environment of type @r@ to the \'strategy\' function.
+-- However, the \'ranking\' function (or more accurately, representation) has no
+-- access to @r@. Put another way, you can influence what values get chosen by
+-- changing @r@, but not how solutions are ranked.
+--
+-- @since 2.3
+deriving via
+  (LiftingSelect (ReaderT r) m)
+  instance
+    (MonadSelect r' m) =>
+    MonadSelect r' (ReaderT r m)
+
+-- | \'Readerizes\' the state: the \'ranking\' function can /see/ a value of
+-- type @s@, but not modify it. Effectively, can be thought of as \'extending\'
+-- the \'ranking\' by all values in @s@, but /which/ @s@ gets given to any rank
+-- calls is predetermined by the \'outer state\' (and cannot change).
+--
+-- @since 2.3
+deriving via
+  (LiftingSelect (LazyState.StateT s) m)
+  instance
+    (MonadSelect w m) =>
+    MonadSelect w (LazyState.StateT s m)
+
+-- | \'Readerizes\' the state: the \'ranking\' function can /see/ a value of
+-- type @s@, but not modify it. Effectively, can be thought of as \'extending\'
+-- the \'ranking\' by all values in @s@, but /which/ @s@ gets given to any rank
+-- calls is predetermined by the \'outer state\' (and cannot change).
+--
+-- @since 2.3
+deriving via
+  (LiftingSelect (StrictState.StateT s) m)
+  instance
+    (MonadSelect w m) =>
+    MonadSelect w (StrictState.StateT s m)
+
+-- | \'Readerizes\' the writer: the \'ranking\' function can see the value
+-- that's been accumulated (of type @w@), but can't add anything to the log.
+-- Effectively, can be thought of as \'extending\' the \'ranking\' by all values
+-- of @w@, but /which/ @w@ gets given to any rank calls is predetermined by the
+-- \'outer writer\' (and cannot change).
+--
+-- @since 2.3
+deriving via
+  (LiftingSelect (CPSWriter.WriterT w) m)
+  instance
+    (MonadSelect w' m) =>
+    MonadSelect w' (CPSWriter.WriterT w m)
+
+-- | \'Readerizes\' the writer: the \'ranking\' function can see the value
+-- that's been accumulated (of type @w@), but can't add anything to the log.
+-- Effectively, can be thought of as \'extending\' the \'ranking\' by all values
+-- of @w@, but /which/ @w@ gets given to any rank calls is predetermined by the
+-- \'outer writer\' (and cannot change).
+--
+-- @since 2.3
+deriving via
+  (LiftingSelect (LazyWriter.WriterT w) m)
+  instance
+    (MonadSelect w' m, Monoid w) =>
+    MonadSelect w' (LazyWriter.WriterT w m)
+
+-- | \'Readerizes\' the writer: the \'ranking\' function can see the value
+-- that's been accumulated (of type @w@), but can't add anything to the log.
+-- Effectively, can be thought of as \'extending\' the \'ranking\' by all values
+-- of @w@, but /which/ @w@ gets given to any rank calls is predetermined by the
+-- \'outer writer\' (and cannot change).
+--
+-- @since 2.3
+deriving via
+  (LiftingSelect (StrictWriter.WriterT w) m)
+  instance
+    (MonadSelect w' m, Monoid w) =>
+    MonadSelect w' (StrictWriter.WriterT w m)
+
+-- | A combination of an \'outer\' 'ReaderT', 'WriterT' and 'StateT'. In short,
+-- you get a value of type @r@ which can influence what gets picked, but not how
+-- anything is ranked, and the \'ranking\' function gets access to an @s@ and a
+-- @w@, but can modify neither.
+--
+-- @since 2.3
+deriving via
+  (LiftingSelect (CPSRWS.RWST r w s) m)
+  instance
+    (MonadSelect w' m) =>
+    MonadSelect w' (CPSRWS.RWST r w s m)
+
+-- | A combination of an \'outer\' 'ReaderT', 'WriterT' and 'StateT'. In short,
+-- you get a value of type @r@ which can influence what gets picked, but not how
+-- anything is ranked, and the \'ranking\' function gets access to an @s@ and a
+-- @w@, but can modify neither.
+--
+-- @since 2.3
+deriving via
+  (LiftingSelect (LazyRWS.RWST r w s) m)
+  instance
+    (MonadSelect w' m, Monoid w) =>
+    MonadSelect w' (LazyRWS.RWST r w s m)
+
+-- | A combination of an \'outer\' 'ReaderT', 'WriterT' and 'StateT'. In short,
+-- you get a value of type @r@ which can influence what gets picked, but not how
+-- anything is ranked, and the \'ranking\' function gets access to an @s@ and a
+-- @w@, but can modify neither.
+--
+-- @since 2.3
+deriving via
+  (LiftingSelect (StrictRWS.RWST r w s) m)
+  instance
+    (MonadSelect w' m, Monoid w) =>
+    MonadSelect w' (StrictRWS.RWST r w s m)
+
+-- | \'Readerizes\' the accumulator: the \'ranking\' function can see the value
+-- that has been accumulated (of type @w@), but can't add anything to it.
+-- Effectively, can be thought of as \'extending\' the \'ranking\' by all values
+-- of @w@, but /which/ @w@ gets given to any rank calls is predetermined by the
+-- \'outer accumulation\' (and cannot change).
+--
+-- @since 2.3
+deriving via
+  (LiftingSelect (AccumT w) m)
+  instance
+    (MonadSelect r m, Monoid w) =>
+    MonadSelect r (AccumT w m)
+
+-- | A helper type to decrease boilerplate when defining new transformer
+-- instances of 'MonadSelect'.
+--
+-- Most of the instances in this module are derived using this method; for
+-- example, our instance of 'ExceptT' is derived as follows:
+--
+-- > deriving via (LiftingSelect (ExceptT e) m) instance (MonadSelect r m) =>
+-- >  MonadSelect r (ExceptT e m)
+--
+-- @since 2.3
+newtype LiftingSelect (t :: (Type -> Type) -> Type -> Type) (m :: Type -> Type) (a :: Type)
+  = LiftingSelect (t m a)
+  deriving
+    ( -- | @since 2.3
+      Functor,
+      -- | @since 2.3
+      Applicative,
+      -- | @since 2.3
+      Monad
+    )
+    via (t m)
+
+-- | @since 2.3
+instance (MonadTrans t, MonadSelect r m, Monad (t m)) => MonadSelect r (LiftingSelect t m) where
+  select f = LiftingSelect . lift $ select f
diff --git a/Control/Monad/State.hs b/Control/Monad/State.hs
--- a/Control/Monad/State.hs
+++ b/Control/Monad/State.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE Safe #-}
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Control.Monad.State
diff --git a/Control/Monad/State/Class.hs b/Control/Monad/State/Class.hs
--- a/Control/Monad/State/Class.hs
+++ b/Control/Monad/State/Class.hs
@@ -1,9 +1,13 @@
-{-# LANGUAGE CPP #-}
+{-# LANGUAGE Safe #-}
 {-# LANGUAGE FunctionalDependencies #-}
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
-{-# LANGUAGE UndecidableInstances #-}
 -- Search for UndecidableInstances to see why this is needed
+{-# LANGUAGE UndecidableInstances #-}
+-- Needed because the CPSed versions of Writer and State are secretly State
+-- wrappers, which don't force such constraints, even though they should legally
+-- be there.
+{-# OPTIONS_GHC -Wno-redundant-constraints #-}
 
 -----------------------------------------------------------------------------
 -- |
@@ -32,23 +36,23 @@
     gets
   ) where
 
-import Control.Monad.Trans.Cont
-import Control.Monad.Trans.Error
-import Control.Monad.Trans.Except
-import Control.Monad.Trans.Identity
-import Control.Monad.Trans.List
-import Control.Monad.Trans.Maybe
-import Control.Monad.Trans.Reader
-import qualified Control.Monad.Trans.RWS.Lazy as LazyRWS (RWST, get, put, state)
-import qualified Control.Monad.Trans.RWS.Strict as StrictRWS (RWST, get, put, state)
-import qualified Control.Monad.Trans.State.Lazy as Lazy (StateT, get, put, state)
-import qualified Control.Monad.Trans.State.Strict as Strict (StateT, get, put, state)
-import Control.Monad.Trans.Writer.Lazy as Lazy
-import Control.Monad.Trans.Writer.Strict as Strict
-
+import Control.Monad.Trans.Cont (ContT)
+import Control.Monad.Trans.Except (ExceptT)
+import Control.Monad.Trans.Identity (IdentityT)
+import Control.Monad.Trans.Maybe (MaybeT) 
+import Control.Monad.Trans.Reader (ReaderT)
+import qualified Control.Monad.Trans.RWS.Lazy as LazyRWS
+import qualified Control.Monad.Trans.RWS.Strict as StrictRWS
+import qualified Control.Monad.Trans.State.Lazy as Lazy
+import qualified Control.Monad.Trans.State.Strict as Strict
+import qualified Control.Monad.Trans.Writer.Lazy as Lazy
+import qualified Control.Monad.Trans.Writer.Strict as Strict
+import Control.Monad.Trans.Accum (AccumT)
+import Control.Monad.Trans.Select (SelectT)
+import qualified Control.Monad.Trans.RWS.CPS as CPSRWS
+import qualified Control.Monad.Trans.Writer.CPS as CPS
 import Control.Monad.Trans.Class (lift)
-import Control.Monad
-import Data.Monoid
+import Data.Functor.Product (Product(..))
 
 -- ---------------------------------------------------------------------------
 
@@ -69,9 +73,7 @@
       let ~(a, s') = f s
       put s'
       return a
-#if __GLASGOW_HASKELL__ >= 707
     {-# MINIMAL state | get, put #-}
-#endif
 
 -- | Monadic state transformer.
 --
@@ -113,6 +115,12 @@
     put = Strict.put
     state = Strict.state
 
+-- | @since 2.3
+instance (Monad m, Monoid w) => MonadState s (CPSRWS.RWST r w s m) where
+    get = CPSRWS.get
+    put = CPSRWS.put
+    state = CPSRWS.state
+
 instance (Monad m, Monoid w) => MonadState s (LazyRWS.RWST r w s m) where
     get = LazyRWS.get
     put = LazyRWS.put
@@ -134,11 +142,6 @@
     put = lift . put
     state = lift . state
 
-instance (Error e, MonadState s m) => MonadState s (ErrorT e m) where
-    get = lift get
-    put = lift . put
-    state = lift . state
-
 -- | @since 2.2
 instance MonadState s m => MonadState s (ExceptT e m) where
     get = lift get
@@ -150,17 +153,18 @@
     put = lift . put
     state = lift . state
 
-instance MonadState s m => MonadState s (ListT m) where
+instance MonadState s m => MonadState s (MaybeT m) where
     get = lift get
     put = lift . put
     state = lift . state
 
-instance MonadState s m => MonadState s (MaybeT m) where
+instance MonadState s m => MonadState s (ReaderT r m) where
     get = lift get
     put = lift . put
     state = lift . state
 
-instance MonadState s m => MonadState s (ReaderT r m) where
+-- | @since 2.3
+instance (Monoid w, MonadState s m) => MonadState s (CPS.WriterT w m) where
     get = lift get
     put = lift . put
     state = lift . state
@@ -174,3 +178,24 @@
     get = lift get
     put = lift . put
     state = lift . state
+
+-- | @since 2.3
+instance
+  ( Monoid w
+  , MonadState s m
+  ) => MonadState s (AccumT w m) where
+    get = lift get
+    put = lift . put
+    state = lift . state
+
+-- | @since 2.3
+instance MonadState s m => MonadState s (SelectT r m) where
+    get = lift get
+    put = lift . put
+    state = lift . state
+
+-- | @since 2.3.2
+instance (MonadState s m, MonadState s n) => MonadState s (Product m n) where
+    get = Pair get get
+    put s = Pair (put s) (put s)
+    state sas = Pair (state sas) (state sas)
diff --git a/Control/Monad/State/Lazy.hs b/Control/Monad/State/Lazy.hs
--- a/Control/Monad/State/Lazy.hs
+++ b/Control/Monad/State/Lazy.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE Safe #-}
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Control.Monad.State.Lazy
@@ -20,10 +21,10 @@
 
 module Control.Monad.State.Lazy (
     -- * MonadState class
-    MonadState(..),
-    modify,
-    modify',
-    gets,
+    MonadState.MonadState(..),
+    MonadState.modify,
+    MonadState.modify',
+    MonadState.gets,
     -- * The State monad
     State,
     runState,
@@ -38,22 +39,17 @@
     execStateT,
     mapStateT,
     withStateT,
-    module Control.Monad,
-    module Control.Monad.Fix,
     module Control.Monad.Trans,
     -- * Examples
     -- $examples
   ) where
 
-import Control.Monad.State.Class
-
+import qualified Control.Monad.State.Class as MonadState
 import Control.Monad.Trans
+
 import Control.Monad.Trans.State.Lazy
         (State, runState, evalState, execState, mapState, withState,
          StateT(StateT), runStateT, evalStateT, execStateT, mapStateT, withStateT)
-
-import Control.Monad
-import Control.Monad.Fix
 
 -- ---------------------------------------------------------------------------
 -- $examples
diff --git a/Control/Monad/State/Strict.hs b/Control/Monad/State/Strict.hs
--- a/Control/Monad/State/Strict.hs
+++ b/Control/Monad/State/Strict.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE Safe #-}
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Control.Monad.State.Strict
@@ -20,10 +21,10 @@
 
 module Control.Monad.State.Strict (
     -- * MonadState class
-    MonadState(..),
-    modify,
-    modify',
-    gets,
+    MonadState.MonadState(..),
+    MonadState.modify,
+    MonadState.modify',
+    MonadState.gets,
     -- * The State monad
     State,
     runState,
@@ -38,22 +39,17 @@
     execStateT,
     mapStateT,
     withStateT,
-    module Control.Monad,
-    module Control.Monad.Fix,
     module Control.Monad.Trans,
     -- * Examples
     -- $examples
   ) where
 
-import Control.Monad.State.Class
-
+import qualified Control.Monad.State.Class as MonadState
 import Control.Monad.Trans
+
 import Control.Monad.Trans.State.Strict
         (State, runState, evalState, execState, mapState, withState,
          StateT(StateT), runStateT, evalStateT, execStateT, mapStateT, withStateT)
-
-import Control.Monad
-import Control.Monad.Fix
 
 -- ---------------------------------------------------------------------------
 -- $examples
diff --git a/Control/Monad/Trans.hs b/Control/Monad/Trans.hs
--- a/Control/Monad/Trans.hs
+++ b/Control/Monad/Trans.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE Safe #-}
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Control.Monad.Trans
diff --git a/Control/Monad/Writer.hs b/Control/Monad/Writer.hs
--- a/Control/Monad/Writer.hs
+++ b/Control/Monad/Writer.hs
@@ -1,3 +1,5 @@
+{-# LANGUAGE Safe #-}
+
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Control.Monad.Writer
diff --git a/Control/Monad/Writer/CPS.hs b/Control/Monad/Writer/CPS.hs
new file mode 100644
--- /dev/null
+++ b/Control/Monad/Writer/CPS.hs
@@ -0,0 +1,47 @@
+{-# LANGUAGE Safe #-}
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Control.Monad.Writer.Strict
+-- Copyright   :  (c) Andy Gill 2001,
+--                (c) Oregon Graduate Institute of Science and Technology, 2001
+-- License     :  BSD-style (see the file LICENSE)
+--
+-- Maintainer  :  libraries@haskell.org
+-- Stability   :  experimental
+-- Portability :  non-portable (multi-param classes, functional dependencies)
+--
+-- Strict writer monads that use continuation-passing-style to achieve constant
+-- space usage.
+--
+--      Inspired by the paper
+--      /Functional Programming with Overloading and Higher-Order Polymorphism/,
+--        Mark P Jones (<http://web.cecs.pdx.edu/~mpj/pubs/springschool.html>)
+--          Advanced School of Functional Programming, 1995.
+--
+-- /Since: mtl-2.3, transformers-0.5.6/
+-----------------------------------------------------------------------------
+
+module Control.Monad.Writer.CPS (
+    -- * MonadWriter class
+    MonadWriter.MonadWriter(..),
+    MonadWriter.listens,
+    MonadWriter.censor,
+    -- * The Writer monad
+    Writer,
+    runWriter,
+    execWriter,
+    mapWriter,
+    -- * The WriterT monad transformer
+    WriterT,
+    writerT,
+    runWriterT,
+    execWriterT,
+    mapWriterT,
+    module Control.Monad.Trans,
+  ) where
+
+import qualified Control.Monad.Writer.Class as MonadWriter
+import Control.Monad.Trans
+import Control.Monad.Trans.Writer.CPS (
+        Writer, runWriter, execWriter, mapWriter,
+        WriterT, writerT, runWriterT, execWriterT, mapWriterT)
diff --git a/Control/Monad/Writer/Class.hs b/Control/Monad/Writer/Class.hs
--- a/Control/Monad/Writer/Class.hs
+++ b/Control/Monad/Writer/Class.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE CPP #-}
+{-# LANGUAGE Safe #-}
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE FunctionalDependencies #-}
 {-# LANGUAGE MultiParamTypeClasses #-}
@@ -30,25 +30,25 @@
     censor,
   ) where
 
-import Control.Monad.Trans.Error as Error
-import Control.Monad.Trans.Except as Except
-import Control.Monad.Trans.Identity as Identity
-import Control.Monad.Trans.Maybe as Maybe
-import Control.Monad.Trans.Reader
-import qualified Control.Monad.Trans.RWS.Lazy as LazyRWS (
-        RWST, writer, tell, listen, pass)
-import qualified Control.Monad.Trans.RWS.Strict as StrictRWS (
-        RWST, writer, tell, listen, pass)
-import Control.Monad.Trans.State.Lazy as Lazy
-import Control.Monad.Trans.State.Strict as Strict
-import qualified Control.Monad.Trans.Writer.Lazy as Lazy (
-        WriterT, writer, tell, listen, pass)
-import qualified Control.Monad.Trans.Writer.Strict as Strict (
-        WriterT, writer, tell, listen, pass)
-
+import Control.Monad.Trans.Except (ExceptT)
+import qualified Control.Monad.Trans.Except as Except
+import Control.Monad.Trans.Identity (IdentityT)
+import qualified Control.Monad.Trans.Identity as Identity
+import Control.Monad.Trans.Maybe (MaybeT)
+import qualified Control.Monad.Trans.Maybe as Maybe
+import Control.Monad.Trans.Reader (ReaderT, mapReaderT)
+import qualified Control.Monad.Trans.RWS.Lazy as LazyRWS 
+import qualified Control.Monad.Trans.RWS.Strict as StrictRWS 
+import qualified Control.Monad.Trans.State.Lazy as Lazy
+import qualified Control.Monad.Trans.State.Strict as Strict
+import qualified Control.Monad.Trans.Writer.Lazy as Lazy
+import qualified Control.Monad.Trans.Writer.Strict as Strict 
+import Control.Monad.Trans.Accum (AccumT)
+import qualified Control.Monad.Trans.Accum as Accum
+import qualified Control.Monad.Trans.RWS.CPS as CPSRWS
+import qualified Control.Monad.Trans.Writer.CPS as CPS
 import Control.Monad.Trans.Class (lift)
-import Control.Monad
-import Data.Monoid
+import Data.Functor.Product (Product(..))
 
 -- ---------------------------------------------------------------------------
 -- MonadWriter class
@@ -63,9 +63,7 @@
 -- the written object.
 
 class (Monoid w, Monad m) => MonadWriter w m | m -> w where
-#if __GLASGOW_HASKELL__ >= 707
     {-# MINIMAL (writer | tell), listen, pass #-}
-#endif
     -- | @'writer' (a,w)@ embeds a simple writer action.
     writer :: (a,w) -> m a
     writer ~(a, w) = do
@@ -103,17 +101,20 @@
     a <- m
     return (a, f)
 
-#if MIN_VERSION_base(4,9,0)
--- | __NOTE__: This instance is only defined for @base >= 4.9.0@.
---
--- @since 2.2.2
+-- | @since 2.2.2
 instance (Monoid w) => MonadWriter w ((,) w) where
   writer ~(a, w) = (w, a)
   tell w = (w, ())
   listen ~(w, a) = (w, (a, w))
   pass ~(w, (a, f)) = (f w, a)
-#endif
 
+-- | @since 2.3
+instance (Monoid w, Monad m) => MonadWriter w (CPS.WriterT w m) where
+    writer = CPS.writer
+    tell   = CPS.tell
+    listen = CPS.listen
+    pass   = CPS.pass
+
 instance (Monoid w, Monad m) => MonadWriter w (Lazy.WriterT w m) where
     writer = Lazy.writer
     tell   = Lazy.tell
@@ -126,6 +127,13 @@
     listen = Strict.listen
     pass   = Strict.pass
 
+-- | @since 2.3
+instance (Monoid w, Monad m) => MonadWriter w (CPSRWS.RWST r w s m) where
+    writer = CPSRWS.writer
+    tell   = CPSRWS.tell
+    listen = CPSRWS.listen
+    pass   = CPSRWS.pass
+
 instance (Monoid w, Monad m) => MonadWriter w (LazyRWS.RWST r w s m) where
     writer = LazyRWS.writer
     tell   = LazyRWS.tell
@@ -144,12 +152,6 @@
 -- All of these instances need UndecidableInstances,
 -- because they do not satisfy the coverage condition.
 
-instance (Error e, MonadWriter w m) => MonadWriter w (ErrorT e m) where
-    writer = lift . writer
-    tell   = lift . tell
-    listen = Error.liftListen listen
-    pass   = Error.liftPass pass
-
 -- | @since 2.2
 instance MonadWriter w m => MonadWriter w (ExceptT e m) where
     writer = lift . writer
@@ -186,3 +188,28 @@
     tell   = lift . tell
     listen = Strict.liftListen listen
     pass   = Strict.liftPass pass
+
+-- | There are two valid instances for 'AccumT'. It could either:
+--
+--   1. Lift the operations to the inner @MonadWriter@
+--   2. Handle the operations itself, à la a @WriterT@.
+--
+--   This instance chooses (1), reflecting that the intent
+--   of 'AccumT' as a type is different than that of @WriterT@.
+--
+-- @since 2.3
+instance
+  ( Monoid w'
+  , MonadWriter w m
+  ) => MonadWriter w (AccumT w' m) where
+    writer = lift . writer
+    tell   = lift . tell
+    listen = Accum.liftListen listen
+    pass   = Accum.liftPass pass
+
+-- | @since 2.3.2
+instance (MonadWriter w m, MonadWriter w n) => MonadWriter w (Product m n) where
+    writer aw           = Pair (writer aw) (writer aw)
+    tell w              = Pair (tell w) (tell w)
+    listen (Pair ma na) = Pair (listen ma) (listen na)
+    pass (Pair maf naf) = Pair (pass maf) (pass naf)
diff --git a/Control/Monad/Writer/Lazy.hs b/Control/Monad/Writer/Lazy.hs
--- a/Control/Monad/Writer/Lazy.hs
+++ b/Control/Monad/Writer/Lazy.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE Safe #-}
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Control.Monad.Writer.Lazy
@@ -19,9 +20,9 @@
 
 module Control.Monad.Writer.Lazy (
     -- * MonadWriter class
-    MonadWriter(..),
-    listens,
-    censor,
+    MonadWriter.MonadWriter(..),
+    MonadWriter.listens,
+    MonadWriter.censor,
     -- * The Writer monad
     Writer,
     runWriter,
@@ -32,19 +33,11 @@
     runWriterT,
     execWriterT,
     mapWriterT,
-    module Control.Monad,
-    module Control.Monad.Fix,
     module Control.Monad.Trans,
-    module Data.Monoid,
   ) where
 
-import Control.Monad.Writer.Class
-
+import qualified Control.Monad.Writer.Class as MonadWriter
 import Control.Monad.Trans
 import Control.Monad.Trans.Writer.Lazy (
         Writer, runWriter, execWriter, mapWriter,
         WriterT(WriterT), runWriterT, execWriterT, mapWriterT)
-
-import Control.Monad
-import Control.Monad.Fix
-import Data.Monoid
diff --git a/Control/Monad/Writer/Strict.hs b/Control/Monad/Writer/Strict.hs
--- a/Control/Monad/Writer/Strict.hs
+++ b/Control/Monad/Writer/Strict.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE Safe #-}
 -----------------------------------------------------------------------------
 -- |
 -- Module      :  Control.Monad.Writer.Strict
@@ -19,9 +20,9 @@
 
 module Control.Monad.Writer.Strict (
     -- * MonadWriter class
-    MonadWriter(..),
-    listens,
-    censor,
+    MonadWriter.MonadWriter(..),
+    MonadWriter.listens,
+    MonadWriter.censor,
     -- * The Writer monad
     Writer,
     runWriter,
@@ -31,19 +32,11 @@
     WriterT(..),
     execWriterT,
     mapWriterT,
-    module Control.Monad,
-    module Control.Monad.Fix,
     module Control.Monad.Trans,
-    module Data.Monoid,
   ) where
 
-import Control.Monad.Writer.Class
-
+import qualified Control.Monad.Writer.Class as MonadWriter
 import Control.Monad.Trans
 import Control.Monad.Trans.Writer.Strict (
         Writer, runWriter, execWriter, mapWriter,
         WriterT(..), execWriterT, mapWriterT)
-
-import Control.Monad
-import Control.Monad.Fix
-import Data.Monoid
diff --git a/README.markdown b/README.markdown
--- a/README.markdown
+++ b/README.markdown
@@ -1,4 +1,164 @@
-The `mtl` Package  [![Hackage](https://img.shields.io/hackage/v/mtl.svg)](https://hackage.haskell.org/package/mtl) [![Build Status](https://travis-ci.org/haskell/mtl.svg)](https://travis-ci.org/haskell/mtl)
-=====================
+# `mtl` [![Hackage](https://img.shields.io/hackage/v/mtl.svg)](https://hackage.haskell.org/package/mtl)
 
-See [`mtl` on Hackage](http://hackage.haskell.org/package/mtl) for more information.
+MTL is a collection of monad classes, extending the `transformers`
+package, using functional dependencies for generic lifting of monadic
+actions.
+
+## Structure
+
+Transformers in MTL are divided into classes and data types. Classes
+define the monadic operations of transformers. Data types, generally
+from the `transformers` package, implement transformers, and MTL
+provides instances for all the transformer type classes.
+
+MTL and `transformers` use a common module, data type, and function
+naming scheme. As an example, let's imagine we have a transformer
+`Foo`.
+
+In the `Control.Monad.Foo` module, we'd find:
+
+* A type class `MonadFoo` with the transformer operations.
+* A data type `FooT` with instances for all monad transformer classes.
+* Functions to run the transformed computation, e.g. `runFooT`. For
+  the actual transformers, there are usually a number of useful runner
+  functions.
+
+### Lifting
+
+When using monad transformers, you often need to "lift" a monadic
+action into your transformed monadic action. This is done using the
+`lift` function from `MonadTrans` in the `Control.Monad.Trans.Class`
+module:
+
+``` haskell
+lift :: (Monad m, MonadTrans t) => m a -> t m a
+```
+
+The action `m a` is lifted into the transformer action `t m a`.
+
+As an example, here we lift an action of type `IO a` into an action of
+type `ExceptT MyError IO a`:
+
+``` haskell
+data MyError = EmptyLine
+
+mightFail :: ExceptT MyError IO ()
+mightFail = do
+  l <- lift getLine
+  when (null l) (throwError EmptyLine)
+```
+
+### Transformers
+
+The following outlines the available monad classes and transformers in
+MTL and `transformers`. For more details, and the corresponding
+documentation of the `mtl` version you are using, see [the
+documentation on Hackage](https://hackage.haskell.org/package/mtl).
+
+* `Control.Monad.Cont`
+
+    The Continuation monad transformer adds the ability to use
+    [continuation-passing style
+    (CPS)](https://en.wikipedia.org/wiki/Continuation-passing_style)
+    in a monadic computation. Continuations can be used to manipulate
+    the control flow of a program, e.g. early exit, error handling, or
+    suspending a computation.
+
+    - Class: `Control.Monad.Cont.Class.MonadCont`
+    - Transformer: `Control.Monad.Cont.ContT`
+
+* `Control.Monad.Error` (deprecated!)
+
+    The Error monad transformer has been deprecated in favor of
+    `Control.Monad.Except`.
+
+* `Control.Monad.Except`
+
+    The Except monad transformer adds the ability to fail with an
+    error in a monadic computation.
+
+    - Class: `Control.Monad.Except.Class.MonadError`
+    - Transformer: `Control.Monad.Except.ExceptT`
+
+* `Control.Monad.Identity`
+
+    The Identity monad transformer does not add any abilities to a
+    monad. It simply applies the bound function to its inner monad
+    without any modification.
+
+    - Transformer: `Control.Monad.Trans.Identity.IdentityT` (in the `transformers` package)
+    - Identity functor and monad: `Data.Functor.Identity.Identity` (in the `base` package)
+
+* `Control.Monad.RWS`
+
+    A convenient transformer that combines the Reader, Writer, and
+    State monad transformers.
+
+    - Lazy transformer: `Control.Monad.RWS.Lazy.RWST` (which is the default, exported by `Control.Monad.RWS`)
+    - Strict transformer: `Control.Monad.RWS.Strict.RWST`
+
+* `Control.Monad.Reader`
+
+    The Reader monad transformer represents a computation which can
+    read values from an environment.
+
+    - Class: `Control.Monad.Reader.Class.MonadReader`
+    - Transformer: `Control.Monad.Reader.ReaderT`
+
+* `Control.Monad.State`
+
+    The State monad transformer represents a computation which can
+    read and write internal state values. If you only need to _read_
+    values, you might want to use
+    [Reader](http://hackage.haskell.org/package/mtl/docs/Control-Monad-Reader.html)
+    instead.
+
+    - Class: `Control.Monad.State.Class.MonadState`
+    - Lazy transformer: `Control.Monad.State.Lazy.StateT` (the default, exported by `Control.Monad.State`)
+    - Strict transformer: `Control.Monad.State.Strict.StateT`
+
+* `Control.Monad.Writer`
+
+    The Writer monad transformer represents a computation that can
+    produce a stream of data in addition to the computed values. This
+    can be used to collect values in some data structure with a
+    `Monoid` instance. This can be used for things like logging and
+    accumulating values throughout a computation.
+
+    - Class: `Control.Monad.Writer.Class.MonadWriter`
+    - Lazy transformers: `Control.Monad.Writer.Lazy.WriterT`
+    - Strict transformers: `Control.Monad.Writer.Strict.WriterT`
+
+* `Control.Monad.Accum`
+
+    The `Accum` monad transformer represents a computation which
+    manages append-only state, or a writer that can read all
+    previous inputs. It binds a function to a monadic value by
+    lazily accumulating subcomputations via `(<>)`. For more general
+    access, use [State](https://hackage.haskell.org/package/transformers-0.6.0.4/docs/Control-Monad-Trans-State.html) instead.
+
+    - Class: `Control.Monad.Accum`
+    - Transformer: `Control.Monad.Trans.Accum.AccumT`
+
+* `Control.Monad.Select`
+
+    The `Select` monad transformer represents a computation which
+    can do backtracking search using a 'ranked' evaluation strategy.
+    Binding a function to a monad value chains together evaluation
+    strategies in the sense that the results of previous strategies
+    may influence subsequent rank and evaluation strategies in
+    subcomputations.
+
+    - Class: `Control.Monad.Select`
+    - Transformer: `Control.Monad.Trans.Select.SelectT`
+
+## Resources
+
+* [`mtl` on Hackage](http://hackage.haskell.org/package/mtl)
+* The [Monad Transformers](http://dev.stephendiehl.com/hask/#monad-transformers)
+  chapter in "What I Wish I Knew When Learning Haskell".
+* References:
+    - This package is inspired by the paper _Functional Programming
+      with Overloading and Higher-Order Polymorphism_, by Mark P
+      Jones, in _Advanced School of Functional Programming_, 1995
+      (<http://web.cecs.pdx.edu/~mpj/pubs/springschool.html>).
diff --git a/mtl.cabal b/mtl.cabal
--- a/mtl.cabal
+++ b/mtl.cabal
@@ -1,33 +1,30 @@
-name:         mtl
-version:      2.2.2
-cabal-version: >= 1.10
-license:      BSD3
-license-file: LICENSE
-author:       Andy Gill
-maintainer:   Edward Kmett <ekmett@gmail.com>
-category:     Control
-synopsis:     Monad classes, using functional dependencies
-homepage:     http://github.com/haskell/mtl
-bug-reports:  http://github.com/haskell/mtl/issues
+cabal-version: 3.0
+name:          mtl
+version:       2.3.2
+license:       BSD-3-Clause
+license-file:  LICENSE
+author:        Andy Gill
+maintainer:    Koz Ross <koz.ross@retro-freedom.nz>
+               Steven Shuck <stevenjshuck@gmail.com>
+category:      Control
+synopsis:      Monad classes for transformers, using functional dependencies
+homepage:      http://github.com/haskell/mtl
+bug-reports:   http://github.com/haskell/mtl/issues
 description:
-    Monad classes using functional dependencies, with instances
-    for various monad transformers, inspired by the paper
-    /Functional Programming with Overloading and Higher-Order Polymorphism/,
-    by Mark P Jones, in /Advanced School of Functional Programming/, 1995
-    (<http://web.cecs.pdx.edu/~mpj/pubs/springschool.html>).
+  MTL is a collection of monad classes, extending the 'transformers'
+  package, using functional dependencies for generic lifting of
+  monadic actions.
+
 build-type: Simple
-extra-source-files: CHANGELOG.markdown, README.markdown
-tested-with:
-  GHC==7.0.4,
-  GHC==7.2.2,
-  GHC==7.4.2,
-  GHC==7.6.3,
-  GHC==7.8.4,
-  GHC==7.10.3,
-  GHC==8.0.2,
-  GHC==8.2.2,
-  GHC==8.4.1
 
+extra-source-files:
+  README.markdown
+
+extra-doc-files:
+  CHANGELOG.markdown
+
+tested-with: GHC ==8.10 || ==9.2 || ==9.8 || ==9.10 || ==9.12, MHS ==0.14.15.0
+
 source-repository head
   type: git
   location: https://github.com/haskell/mtl.git
@@ -36,13 +33,12 @@
   exposed-modules:
     Control.Monad.Cont
     Control.Monad.Cont.Class
-    Control.Monad.Error
     Control.Monad.Error.Class
     Control.Monad.Except
     Control.Monad.Identity
-    Control.Monad.List
     Control.Monad.RWS
     Control.Monad.RWS.Class
+    Control.Monad.RWS.CPS
     Control.Monad.RWS.Lazy
     Control.Monad.RWS.Strict
     Control.Monad.Reader
@@ -54,24 +50,19 @@
     Control.Monad.Trans
     Control.Monad.Writer
     Control.Monad.Writer.Class
+    Control.Monad.Writer.CPS
     Control.Monad.Writer.Lazy
     Control.Monad.Writer.Strict
-  build-depends: base < 5, transformers >= 0.4 && <0.6
-
-  default-language: Haskell2010
-  other-extensions:
-    CPP
-    MultiParamTypeClasses
-    FunctionalDependencies
-    FlexibleInstances
-    UndecidableInstances
+    Control.Monad.Accum
+    Control.Monad.Select
 
-  -- This is a SafeHaskell safeguard (pun intended) to explicitly declare the API contract of `mtl`
-  -- GHC versions before 7.4 were hopelessly broken or incapable of SafeHaskell
-  if impl(ghc >= 7.4)
-    default-extensions: Safe
+  build-depends:
+    , base >=4.12 && < 5
+    , transformers >= 0.5.6 && <0.7
 
-  ghc-options: -Wall -fno-warn-unused-imports -fno-warn-warnings-deprecations
+  ghc-options:
+    -Wall -Wcompat -Wincomplete-record-updates
+    -Wincomplete-uni-patterns -Wredundant-constraints
+    -Wmissing-export-lists
 
-  if impl(ghc >= 8.0)
-    ghc-options: -Wcompat -Wnoncanonical-monad-instances -Wnoncanonical-monadfail-instances
+  default-language: Haskell2010
