diff --git a/CHANGELOG.markdown b/CHANGELOG.markdown
--- a/CHANGELOG.markdown
+++ b/CHANGELOG.markdown
@@ -1,3 +1,12 @@
+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
diff --git a/Control/Monad/Accum.hs b/Control/Monad/Accum.hs
--- a/Control/Monad/Accum.hs
+++ b/Control/Monad/Accum.hs
@@ -83,6 +83,22 @@
   ( -- * 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 (..),
 
@@ -109,7 +125,6 @@
 import qualified Control.Monad.Trans.Writer.Lazy as LazyWriter
 import qualified Control.Monad.Trans.Writer.Strict as StrictWriter
 import Data.Functor (($>))
-import Data.Functor.Identity (Identity)
 import Data.Kind (Type)
 
 -- | The capability to accumulate. This can be seen in one of two ways:
@@ -125,7 +140,7 @@
 --
 -- 1. @'accum' ('const' (x, 'mempty'))@ @=@ @'pure' x@
 -- 2. @'accum' f '*>' 'accum' g@ @=@
--- @'accum' '$' \acc -> let (_, v) = f acc
+-- @'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
@@ -134,14 +149,14 @@
 -- 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@
+-- 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@
+-- 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
@@ -160,7 +175,7 @@
   {-# MINIMAL accum | look, add #-}
 
 -- | @since 2.3
-instance (Monoid w) => MonadAccum w (AccumT w Identity) where
+instance (Monoid w, Monad m) => MonadAccum w (AccumT w m) where
   look = Accum.look
   add = Accum.add
   accum = Accum.accum
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,3 +1,4 @@
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE RankNTypes #-}
 {-# LANGUAGE Safe #-}
 {-# LANGUAGE PolyKinds #-}
@@ -113,7 +114,12 @@
     {-# MINIMAL callCC #-}
 
 -- | @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
 
 -- ---------------------------------------------------------------------------
@@ -185,11 +191,13 @@
 --
 -- = Note
 --
--- For any function @f@, @'liftCallCC f'@ satisfies the [uniformity
+-- 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
+-- @
+-- '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. 
@@ -203,6 +211,10 @@
 -- @since 2.3.1
 liftCallCC :: 
   forall (t :: (Type -> Type) -> Type -> Type) (m :: Type -> Type) (a :: Type) (b :: Type) . 
-  (MonadTrans t, Monad m, forall (m' :: Type -> Type) . Monad m' => Monad (t m')) => 
+  (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/Class.hs b/Control/Monad/Error/Class.hs
--- a/Control/Monad/Error/Class.hs
+++ b/Control/Monad/Error/Class.hs
@@ -48,6 +48,7 @@
     tryError,
     withError,
     handleError,
+    onError,
     mapError,
     modifyError,
   ) where
@@ -72,9 +73,10 @@
 import qualified Control.Monad.Trans.Writer.CPS as CPSWriter
 import Control.Monad.Trans.Class (lift)
 import Control.Exception (IOException, catch, ioError)
-import Control.Monad (Monad)
+import Control.Monad (Monad ((>>=), (>>)))
+import Data.Functor.Product (Product(..))
 import Data.Monoid (Monoid)
-import Prelude (Either (Left, Right), Maybe (Nothing), either, flip, (.), IO, pure, (<$>), (>>=))
+import Prelude (Either (Left, Right), Maybe (Nothing), either, flip, (.), IO, pure, (<$>))
 
 {- |
 The strategy of combining computations that can throw exceptions
@@ -205,7 +207,17 @@
     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)
 
@@ -213,17 +225,31 @@
 -- 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 action = tryError action >>= either (throwError . f) pure
+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
 
diff --git a/Control/Monad/Except.hs b/Control/Monad/Except.hs
--- a/Control/Monad/Except.hs
+++ b/Control/Monad/Except.hs
@@ -41,6 +41,7 @@
     Error.tryError,
     Error.withError,
     Error.handleError,
+    Error.onError,
     Error.mapError,
     Error.modifyError,
     -- * The ExceptT monad transformer
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
@@ -41,6 +41,7 @@
 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.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
@@ -62,3 +63,6 @@
 instance MonadRWS r w s m => MonadRWS r w s (ExceptT 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/Reader/Class.hs b/Control/Monad/Reader/Class.hs
--- a/Control/Monad/Reader/Class.hs
+++ b/Control/Monad/Reader/Class.hs
@@ -69,6 +69,7 @@
 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 Data.Functor.Product (Product(..))
 
 -- ----------------------------------------------------------------------------
 -- class MonadReader
@@ -202,3 +203,8 @@
       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/State/Class.hs b/Control/Monad/State/Class.hs
--- a/Control/Monad/State/Class.hs
+++ b/Control/Monad/State/Class.hs
@@ -52,6 +52,7 @@
 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 Data.Functor.Product (Product(..))
 
 -- ---------------------------------------------------------------------------
 
@@ -192,3 +193,9 @@
     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/Writer/CPS.hs b/Control/Monad/Writer/CPS.hs
--- a/Control/Monad/Writer/CPS.hs
+++ b/Control/Monad/Writer/CPS.hs
@@ -33,6 +33,8 @@
     mapWriter,
     -- * The WriterT monad transformer
     WriterT,
+    writerT,
+    runWriterT,
     execWriterT,
     mapWriterT,
     module Control.Monad.Trans,
@@ -42,4 +44,4 @@
 import Control.Monad.Trans
 import Control.Monad.Trans.Writer.CPS (
         Writer, runWriter, execWriter, mapWriter,
-        WriterT, execWriterT, mapWriterT)
+        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
@@ -48,6 +48,7 @@
 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 Data.Functor.Product (Product(..))
 
 -- ---------------------------------------------------------------------------
 -- MonadWriter class
@@ -205,3 +206,10 @@
     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/README.markdown b/README.markdown
--- a/README.markdown
+++ b/README.markdown
@@ -1,4 +1,4 @@
-# `mtl` [![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)
 
 MTL is a collection of monad classes, extending the `transformers`
 package, using functional dependencies for generic lifting of monadic
diff --git a/mtl.cabal b/mtl.cabal
--- a/mtl.cabal
+++ b/mtl.cabal
@@ -1,12 +1,11 @@
 cabal-version: 3.0
 name:          mtl
-version:       2.3.1
+version:       2.3.2
 license:       BSD-3-Clause
 license-file:  LICENSE
 author:        Andy Gill
-maintainer:    chessai <chessai1996@gmail.com>,
-               Emily Pillmore <emilypi@cohomolo.gy>,
-               Koz Ross <koz.ross@retro-freedom.nz>
+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
@@ -19,10 +18,12 @@
 build-type: Simple
 
 extra-source-files:
-  CHANGELOG.markdown
   README.markdown
 
-tested-with: GHC ==8.6.5 || ==8.8.4 || ==8.10.7 || ==9.0.2 || ==9.2.4 || ==9.4.1
+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
