diff --git a/CHANGES.markdown b/CHANGES.markdown
--- a/CHANGES.markdown
+++ b/CHANGES.markdown
@@ -1,7 +1,173 @@
+0.6.2.1 (19 January 2026)
+-------------------------
+
+- Test with GHC 9.14
+- Drop support for GHC < 8
+- Drop `transformers-compat` dependency
+
+0.6.2 (5 March 2025)
+--------------------
+
+- Support `random-1.3`.  Thanks to @bgamari and @lehins for help
+  making the necessary updates.
+
+0.6.1 (22 October 2024)
+-----------------------
+
+- Fix the potential for a crash in `fromListMay` (and hence also in
+  functions that use it, namely `fromList`, `weighted`, `weightedMay`,
+  `uniform`, and `uniformMay`). Thanks to @Flupp for pointing out the
+  issue and suggesting a fix.  The fix may in theory cause these
+  functions, extremely rarely, to output values different from the old
+  values for the same seed.  See
+  https://byorgey.github.io/blog/posts/2024/10/14/MonadRandom-version-bump.html
+  for more information and discussion.
+
+0.6 (5 Nov 2022)
+----------------
+
+- Remove instances for deprecated `ErrorT` and `ListT` transformers
+- Allow building with `transformers-0.6` and `mtl-2.3.1`
+- Drop support for GHC 7.6 and 7.8
+
+- r1 (18 Dec 2022): require `base >= 4.8`
+- r2 (9 Jan 2023): require `random >= 1.0.1`
+- r3 (22 Feb 2023): allow `primitive-0.8`
+- r4 (12 Oct 2023): allow `primitive-0.9`, test on GHC 9.6 and 9.8
+
+0.5.3 (8 April 2021)
+--------------------
+
+- `StatefulGen` instances for `RandT`
+- Addition of `RandGen`
+- Addition of `withRandGen` and `withRandGen_`
+
+- r1 (28 April 2021): require `base >= 4.6`
+- r2 (9 Aug 2021): allow `transformers-compat-0.7`.
+- r3 (9 Aug 2022): Test with GHC 9.0-9.4
+
+0.5.2 (24 June 2020)
+--------------------
+
+- Support for `random-1.2`.
+- Drop support for GHC 7.4, test with GHC 8.10.
+
+0.5.1.2 (18 Jan 2020)
+---------------------
+
+- Better error message when total probability sum is negative in
+  fromListMay, weightedMay, weighted
+
+0.5.1.1 (21 May 2018)
+---------------------
+
+- Only depend on `fail` package when GHC < 8.0.
+
+0.5.1 (9 February 2017)
+-----------------------
+
+Re-export `System.Random` from `Control.Monad.Random.{Lazy,Strict}`
+and hence also from `Control.Monad.Random`.
+
+- Hackage r1: allow `transformers-compat-0.6.x`.
+
+0.5 (3 January 2017)
+--------------------
+
+  This release has quite a few small additions as well as a big module
+  reorganization.  However, thanks to module re-exports, most existing
+  code using the library should continue to work with no changes; the
+  major version bump reflects the large reorganization and my
+  inability to 100% guarantee that existing user code will not break.
+
+  The biggest changes that may be of interest to users of the library
+  include new lazy vs strict variants of the `Rand` monad; a new
+  `MonadInterleave` class which is a big improvement over
+  `MonadSplit`; new `PrimMonad` instances; and new random selection
+  functions like `weighted`, `weightedMay`, `uniformMay`, *etc.*.  See
+  the list below for full details.
+
+  Although there was some discussion of generalizing `MonadRandom` to
+  work for a wider range of underlying generators
+  (see
+  [#26](https://github.com/byorgey/MonadRandom/issues/26),
+  [#31](https://github.com/byorgey/MonadRandom/issues/31), and
+  [comments on this blog post](https://byorgey.wordpress.com/2016/11/16/monadrandom-0-5-and-mwc-random-feedback-wanted/)),
+  I decided to punt on that for now. It seems rather complicated and
+  there
+  are
+  [already good alternatives](http://hackage.haskell.org/package/random%2Dfu) so
+  I decided to keep things simple for this release.  I'm still open to
+  proposals for generalizing future releases.
+
+  Changes in 0.5 include:
+
+  - Refactor to reflect structure of `mtl` and `transformers` libraries.
+  - Add lazy and strict variants of `RandT`.
+  - Add `MonadRandom` and `MonadSplit` instances for `ListT`.
+  - Add (but do not export) `unRandT` field to `RandT`.
+  - Add `MonadCont`, `MonadError`, `MonadRWS`, `PrimMonad`, and `MonadFail`
+    instances for `RandT`.
+  - Add `evalRandTIO` operation.
+  - Move `fromList` and `uniform` operations to
+    `Control.Monad.Random.Class`.
+  - `fromList` now raises an error when the total weight of elements
+    is zero.
+  - Generalize the type of `uniform` to work over any `Foldable`.
+  - Add new operations `weighted`, `weightedMay`, `fromListMay`, and
+    `uniformMay`.  `weighted` is like `fromList` but generalized to
+    work over any `Foldable`.  The `May` variants return a `Maybe`
+    result instead of raising an error.
+  - New `MonadInterleave` class for random monads which can interleave
+    random generation using `split`.  In some ways this is similar to
+    `MonadSplit` but much more useful.
+  - Improved documentation.
+
+0.4.2.3 (21 April 2016)
+-----------------------
+
+  - Mark `Control.Monad.Random` as `Trustworthy`.
+
+0.4.2.2 (18 January 2016)
+-------------------------
+
+  - Allow `transformers-0.5`.
+
+0.4.2.1 (16 January 2016)
+-------------------------
+
+  - Allow `transformers-compat-0.5`.
+
+0.4.2 (16 January 2016)
+-----------------------
+
+  - Add `MonadPlus` and `Alternative` instances for `RandT`.
+
+0.4.1 (20 November 2015)
+------------------------
+
+  - Remove unnecessary `Monad m` constraint from `liftRandT` and
+    `runRandT`.
+
+  This should again technically require a major version bump, but I'm
+  not doing it this time in the interest of not being super annoying.
+  If this breaks something for you, just yell, and I will
+  deprecate this version and do a proper 0.5 release.
+
+0.4 (12 May 2015)
+-----------------
+
+  - Remove unnecessary `RandomGen g` constraints from `liftRandT`,
+    `liftRand`, `evalRandT`, `evalRand`, `runRandT`, `runRand`.
+
+  A major version bump is required by the PVP since the types of all
+  the above methods have changed, but this release is again very
+  unlikely to break any client code.
+
 0.3.0.2 (30 March 2015)
 -----------------------
 
-  - Add transformers-compat to allow building with newer mtl
+  - Add `transformers-compat` to allow building with newer `mtl`
 
 0.3.0.1 (24 November 2014)
 --------------------------
@@ -22,7 +188,7 @@
 0.2.0.1 (24 August 2014)
 ------------------------
 
-  - Allow building with both transformers-0.3 and 0.4.
+  - Allow building with both `transformers-0.3` and `0.4`.
 
 0.2 (20 August 2014)
 --------------------
@@ -37,29 +203,29 @@
 0.1.13 (9 February 2014)
 ------------------------
 
-  - add simple 'uniform' function for creating a uniform distribution
+  - add simple `uniform` function for creating a uniform distribution
     over a list of values
 
 0.1.12 (30 September 2013)
 --------------------------
 
-  - add liftRandT and liftRand functions, for lifting explicit
-    generator-passing functions into RandT and Rand, respectively.
+  - add `liftRandT` and `liftRand` functions, for lifting explicit
+    generator-passing functions into `RandT` and `Rand`, respectively.
 
 0.1.11 (1 August 2013)
 ----------------------
 
-  - add MonadRandom and MonadSplit instances for IdentityT
-  - derive MonadReader and MonadWriter instances instead of declaring
+  - add `MonadRandom` and `MonadSplit` instances for `IdentityT`
+  - derive `MonadReader` and `MonadWriter` instances instead of declaring
     them explicitly (thanks again to James Koppel)
 
 0.1.10 (16 July 2013)
 ---------------------
 
-  - add MonadRandom and MonadSplit instances for ContT
+  - add `MonadRandom` and `MonadSplit` instances for `ContT`
     (thanks to James Koppel for the patch)
 
 0.1.9 (26 April 2013)
 ---------------------
 
-  - add MonadRandom and MonadSplit instances for MaybeT
+  - add `MonadRandom` and `MonadSplit` instances for `MaybeT`
diff --git a/Control/Monad/Random.hs b/Control/Monad/Random.hs
--- a/Control/Monad/Random.hs
+++ b/Control/Monad/Random.hs
@@ -1,291 +1,20 @@
-{-# LANGUAGE CPP                        #-}
-{-# LANGUAGE FlexibleInstances          #-}
-{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-{-# LANGUAGE MultiParamTypeClasses      #-}
-{-# LANGUAGE UndecidableInstances       #-}
-{-# OPTIONS -fno-warn-orphans #-}
+{-# LANGUAGE Safe #-}
 
 {- |
-Copyright    : 2006-2007 Cale Gibbard, Russell O'Connor, Dan Doel, Remi Turk, Eric Kidd.
-License      : OtherLicense
-Stability    : experimental
-Portability  : non-portable (multi-parameter type classes, undecidable instances)
-
-A random number generation monad.  See
-<http://www.haskell.org/haskellwiki/NewMonads/MonadRandom> for the original
-version of this code.
-
-The actual interface is defined by
-'Control.Monad.Random.Class.MonadRandom'.
-
-[Computation type:] Computations which consume random values.
-
-[Binding strategy:] The computation proceeds in the same fashion as the
-identity monad, but it carries a random number generator that may be
-queried to generate random values.
+Module       :  Control.Monad.Random
+Copyright    :  (c) Brent Yorgey 2016
+License      :  BSD3 (see LICENSE)
 
-[Useful for:] Monte Carlo algorithms and simulating random processes.
+Maintainer   :  byorgey@gmail.com
+Stability    :  experimental
+Portability  :  non-portable (multi-param classes, functional dependencies, undecidable instances)
 
+This module is provided for backwards compatibility, and simply
+re-exports "Control.Monad.Random.Lazy".
 -}
 
-module Control.Monad.Random (
-    module System.Random,
-    module Control.Monad.Random.Class,
-    evalRandT,
-    runRandT,
-    evalRand,
-    runRand,
-    evalRandIO,
-    fromList,
-    uniform,
-    Rand, RandT, -- but not the data constructors
-    -- * Special lift functions
-    liftRand,
-    liftRandT
-    -- * Example
-    -- $RandExample
+module Control.Monad.Random
+    ( module Control.Monad.Random.Lazy,
     ) where
 
-import           Control.Applicative
-import           Control.Arrow
-import           Control.Monad                ()
-import           Control.Monad.Cont
-import           Control.Monad.Error
-import           Control.Monad.Identity
-import           Control.Monad.Random.Class
-import           Control.Monad.Reader
-import qualified Control.Monad.RWS.Lazy       as RWSL
-import qualified Control.Monad.RWS.Strict     as RWSS
-import           Control.Monad.State
-import qualified Control.Monad.State.Lazy     as SL
-import qualified Control.Monad.State.Strict   as SS
-import           Control.Monad.Trans          ()
-import           Control.Monad.Trans.Except
-import           Control.Monad.Trans.Identity
-import           Control.Monad.Trans.Maybe
-import           Control.Monad.Writer.Class
-import qualified Control.Monad.Writer.Lazy    as WL
-import qualified Control.Monad.Writer.Strict  as WS
-import           Data.Monoid                  (Monoid)
-import           System.Random
-
--- | A monad transformer which adds a random number generator to an
--- existing monad.
-newtype RandT g m a = RandT (StateT g m a)
-    deriving (Functor, Monad, MonadTrans, MonadIO, MonadFix, MonadReader r, MonadWriter w)
-
-instance (Functor m,Monad m) => Applicative (RandT g m) where
-  pure = return
-  (<*>) = ap
-
--- | Lift arbitrary action to RandT
-liftRandT :: (Monad m, RandomGen g) =>
-             (g -> m (a, g)) -- ^ action returning value and new generator state
-             -> RandT g m a
-liftRandT = RandT . StateT
-
--- | Lift arbitrary action to Rand
-liftRand :: (RandomGen g) =>
-            (g -> (a, g)) -- ^ action returning value and new generator state
-            -> Rand g a
-liftRand = RandT . state
-
-instance (Monad m, RandomGen g) => MonadRandom (RandT g m) where
-    getRandom = RandT . state $ random
-    getRandoms = RandT . state $ first randoms . split
-    getRandomR (x,y) = RandT . state $ randomR (x,y)
-    getRandomRs (x,y) = RandT . state $
-                            first (randomRs (x,y)) . split
-
-instance (Monad m, RandomGen g) => MonadSplit g (RandT g m) where
-    getSplit = RandT . state $ split
-
--- | Evaluate a RandT computation using the generator @g@.  Note that the
--- generator @g@ is not returned, so there's no way to recover the
--- updated version of @g@.
-evalRandT :: (Monad m, RandomGen g) => RandT g m a -> g -> m a
-evalRandT (RandT x) g = evalStateT x g
-
--- | Run a RandT computation using the generator @g@, returning the result and
--- the updated generator.
-runRandT  :: (Monad m, RandomGen g) => RandT g m a -> g -> m (a, g)
-runRandT (RandT x) g = runStateT x g
-
--- | A basic random monad.
-type Rand g = RandT g Identity
-
--- | Evaluate a random computation using the generator @g@.  Note that the
--- generator @g@ is not returned, so there's no way to recover the
--- updated version of @g@.
-evalRand :: (RandomGen g) => Rand g a -> g -> a
-evalRand x g = runIdentity (evalRandT x g)
-
--- | Run a random computation using the generator @g@, returning the result
--- and the updated generator.
-runRand :: (RandomGen g) => Rand g a -> g -> (a, g)
-runRand x g = runIdentity (runRandT x g)
-
--- | Evaluate a random computation in the IO monad, splitting the global standard generator to get a new one for the computation.
-evalRandIO :: Rand StdGen a -> IO a
-evalRandIO x = fmap (evalRand x) newStdGen
-
--- | Sample a random value from a weighted list.  The total weight of all
--- elements must not be 0.
-fromList :: (MonadRandom m) => [(a,Rational)] -> m a
-fromList [] = error "MonadRandom.fromList called with empty list"
-fromList [(x,_)] = return x
-fromList xs = do
-  -- TODO: Do we want to be able to use floats as weights?
-  -- TODO: Better error message if weights sum to 0.
-  let s = (fromRational (sum (map snd xs))) :: Double -- total weight
-      cs = scanl1 (\(_,q) (y,s') -> (y, s'+q)) xs       -- cumulative weight
-  p <- liftM toRational $ getRandomR (0.0,s)
-  return . fst . head $ dropWhile (\(_,q) -> q < p) cs
-
--- | Sample a value from a uniform distribution of a list of elements.
-uniform :: (MonadRandom m) => [a] -> m a
-uniform = fromList . fmap (flip (,) 1)
-
-instance (MonadRandom m) => MonadRandom (IdentityT m) where
-    getRandom = lift getRandom
-    getRandomR = lift . getRandomR
-    getRandoms = lift getRandoms
-    getRandomRs = lift . getRandomRs
-
-instance (MonadRandom m) => MonadRandom (SL.StateT s m) where
-    getRandom = lift getRandom
-    getRandomR = lift . getRandomR
-    getRandoms = lift getRandoms
-    getRandomRs = lift . getRandomRs
-
-instance (MonadRandom m) => MonadRandom (SS.StateT s m) where
-    getRandom = lift getRandom
-    getRandomR = lift . getRandomR
-    getRandoms = lift getRandoms
-    getRandomRs = lift . getRandomRs
-
-instance (MonadRandom m, Monoid w) => MonadRandom (WL.WriterT w m) where
-    getRandom = lift getRandom
-    getRandomR = lift . getRandomR
-    getRandoms = lift getRandoms
-    getRandomRs = lift . getRandomRs
-
-instance (MonadRandom m, Monoid w) => MonadRandom (WS.WriterT w m) where
-    getRandom = lift getRandom
-    getRandomR = lift . getRandomR
-    getRandoms = lift getRandoms
-    getRandomRs = lift . getRandomRs
-
-instance (MonadRandom m) => MonadRandom (ReaderT r m) where
-    getRandom = lift getRandom
-    getRandomR = lift . getRandomR
-    getRandoms = lift getRandoms
-    getRandomRs = lift . getRandomRs
-
-instance (MonadRandom m, Monoid w) => MonadRandom (RWSL.RWST r w s m) where
-    getRandom = lift getRandom
-    getRandomR = lift . getRandomR
-    getRandoms = lift getRandoms
-    getRandomRs = lift . getRandomRs
-
-instance (MonadRandom m, Monoid w) => MonadRandom (RWSS.RWST r w s m) where
-    getRandom = lift getRandom
-    getRandomR = lift . getRandomR
-    getRandoms = lift getRandoms
-    getRandomRs = lift . getRandomRs
-
-instance (MonadRandom m) => MonadRandom (ExceptT e m) where
-    getRandom = lift getRandom
-    getRandomR = lift . getRandomR
-    getRandoms = lift getRandoms
-    getRandomRs = lift . getRandomRs
-
-instance (Error e, MonadRandom m) => MonadRandom (ErrorT e m) where
-    getRandom = lift getRandom
-    getRandomR = lift . getRandomR
-    getRandoms = lift getRandoms
-    getRandomRs = lift . getRandomRs
-
-instance (MonadRandom m) => MonadRandom (MaybeT m) where
-    getRandom = lift getRandom
-    getRandomR = lift . getRandomR
-    getRandoms = lift getRandoms
-    getRandomRs = lift . getRandomRs
-
-instance MonadRandom m => MonadRandom (ContT r m) where
-    getRandom = lift getRandom
-    getRandomR = lift . getRandomR
-    getRandoms = lift getRandoms
-    getRandomRs = lift . getRandomRs
-
-instance (MonadSplit g m) => MonadSplit g (IdentityT m) where
-    getSplit = lift getSplit
-
-instance (MonadSplit g m) => MonadSplit g (SL.StateT s m) where
-    getSplit = lift getSplit
-
-instance (MonadSplit g m) => MonadSplit g (SS.StateT s m) where
-    getSplit = lift getSplit
-
-instance (MonadSplit g m, Monoid w) => MonadSplit g (WL.WriterT w m) where
-    getSplit = lift getSplit
-
-instance (MonadSplit g m, Monoid w) => MonadSplit g (WS.WriterT w m) where
-    getSplit = lift getSplit
-
-instance (MonadSplit g m) => MonadSplit g (ReaderT r m) where
-    getSplit = lift getSplit
-
-instance (MonadSplit g m, Monoid w) => MonadSplit g (RWSL.RWST r w s m) where
-    getSplit = lift getSplit
-
-instance (MonadSplit g m, Monoid w) => MonadSplit g (RWSS.RWST r w s m) where
-    getSplit = lift getSplit
-
-instance (MonadSplit g m) => MonadSplit g (ExceptT e m) where
-    getSplit = lift getSplit
-
-instance (Error e, MonadSplit g m) => MonadSplit g (ErrorT e m) where
-    getSplit = lift getSplit
-
-instance (MonadSplit g m) => MonadSplit g (MaybeT m) where
-    getSplit = lift getSplit
-
-instance (MonadSplit g m) => MonadSplit g (ContT r m) where
-    getSplit = lift getSplit
-
-instance (MonadState s m) => MonadState s (RandT g m) where
-    get = lift get
-    put = lift . put
-
-instance MonadRandom IO where
-    getRandom = randomIO
-    getRandomR = randomRIO
-    getRandoms = fmap randoms newStdGen
-    getRandomRs b = fmap (randomRs b) newStdGen
-
-instance MonadSplit StdGen IO where
-    getSplit = newStdGen
-
-{- $RandExample
-
-The @die@ function simulates the roll of a die, picking a number between 1
-and 6, inclusive, and returning it in the 'Rand' monad.  Notice that this
-code will work with any source of random numbers @g@.
-
->die :: (RandomGen g) => Rand g Int
->die = getRandomR (1,6)
-
-The @dice@ function uses @replicate@ and @sequence@ to simulate the roll of
-@n@ dice.
-
->dice :: (RandomGen g) => Int -> Rand g [Int]
->dice n = sequence (replicate n die)
-
-To extract a value from the 'Rand' monad, we can can use 'evalRandIO'.
-
->main = do
->  values <- evalRandIO (dice 2)
->  putStrLn (show values)
-
--}
+import           Control.Monad.Random.Lazy
diff --git a/Control/Monad/Random/Class.hs b/Control/Monad/Random/Class.hs
--- a/Control/Monad/Random/Class.hs
+++ b/Control/Monad/Random/Class.hs
@@ -1,50 +1,397 @@
-{-# LANGUAGE MultiParamTypeClasses, UndecidableInstances, FunctionalDependencies #-}
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE FunctionalDependencies #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE Safe #-}
+{-# LANGUAGE UndecidableInstances #-}
 
-{- |
-Copyright    : 2006-2007 Cale Gibbard, Russell O'Connor, Dan Doel, Remi Turk, Eric Kidd.
-License      : OtherLicense
-Stability    : experimental
-Portability  : non-portable (multi-parameter type classes, undecidable instances)
+-- |
+-- Module       :  Control.Monad.Random.Class
+-- Copyright    :  (c) Brent Yorgey 2016
+-- License      :  BSD3 (see LICENSE)
+-- Maintainer   :  byorgey@gmail.com
+--
+-- The 'MonadRandom', 'MonadSplit', and 'MonadInterleave' classes.
+--
+-- * 'MonadRandom' abstracts over monads with the capability of
+--   generating random values.
+--
+-- * 'MonadSplit' abstracts over random monads with the ability to get a
+--   split generator state.  It is not very useful but kept here for
+--   backwards compatibility.
+--
+-- * 'MonadInterleave' abstracts over random monads supporting an
+--   'interleave' operation, which allows sequencing computations which do
+--   not depend on each other's random generator state, by splitting the
+--   generator between them.
+--
+-- This module also defines convenience functions for sampling from a
+-- given collection of values, either uniformly or according to given
+-- weights.
+module Control.Monad.Random.Class (
+  -- * MonadRandom
+  MonadRandom (..),
 
-A type class for random number generation monads.  See
-<http://www.haskell.org/haskellwiki/NewMonads/MonadRandom> for the original
-version of this code.
+  -- * MonadSplit
+  MonadSplit (..),
 
-Instances of this type class include 'Control.Monad.Random.Rand' and
-monads created using 'Control.Monad.Random.RandT'.
+  -- * MonadInterleave
+  MonadInterleave (..),
 
--}
+  -- * Sampling functions
+  fromList,
+  fromListMay,
+  uniform,
+  uniformMay,
+  weighted,
+  weightedMay,
+) where
 
-module Control.Monad.Random.Class (
-    MonadRandom,
-    getRandom,
-    getRandomR,
-    getRandoms,
-    getRandomRs,
-    MonadSplit,
-    getSplit
-    ) where
+import Control.Monad
+import Control.Monad.Trans.Class
+import Control.Monad.Trans.Cont
+import Control.Monad.Trans.Except
+import Control.Monad.Trans.Identity
+import Control.Monad.Trans.Maybe
+import qualified Control.Monad.Trans.RWS.Lazy as LazyRWS
+import qualified Control.Monad.Trans.RWS.Strict as StrictRWS
+import Control.Monad.Trans.Reader
+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 qualified Data.Foldable as F
+import Data.Word (Word64)
+import qualified System.Random as Random
 
-import System.Random
+#if MIN_VERSION_base(4,8,0)
+#else
+import           Data.Monoid                       (Monoid)
+#endif
 
--- | An interface to random number generation monads.
-class (Monad m) => MonadRandom m where
-    -- | Return a randomly-selected value of type @a@.  See
-    -- 'System.Random.random' for details.
-    getRandom :: (Random a) => m a
-    -- | Return an infinite stream of random values of type @a@.  See
-    -- 'System.Random.randoms' for details.
-    getRandoms :: (Random a) => m [a]
-    -- | Return a randomly-selected value of type @a@ in the range
-    -- /[lo,hi]/.  See 'System.Random.randomR' for details.
-    getRandomR :: (Random a) => (a,a) -> m a
-    -- | Return an infinite stream of randomly-selected value of type @a@
-    -- in the range /[lo,hi]/.  See 'System.Random.randomRs' for details.
-    getRandomRs :: (Random a) => (a,a) -> m [a]
+------------------------------------------------------------
+-- MonadRandom
+------------------------------------------------------------
 
--- | An interface to monads with splittable state (as most random number generation monads will have).
--- The intention is that the 'getSplit' action splits the state, returning one half of the result, and
--- setting the new state to the other.
-class (Monad m) => MonadSplit s m | m -> s where
-    getSplit :: m s
+-- | With a source of random number supply in hand, the 'MonadRandom' class
+-- allows the programmer to extract random values of a variety of types.
+class Monad m => MonadRandom m where
+  -- | Takes a range /(lo,hi)/ and a random number generator
+  -- /g/, and returns a computation that returns a random value uniformly
+  -- distributed in the closed interval /[lo,hi]/, together with a new
+  -- generator. It is unspecified what happens if /lo>hi/. For continuous
+  -- types there is no requirement that the values /lo/ and /hi/ are ever
+  -- produced, but they may be, depending on the implementation and the
+  -- interval.
+  --
+  -- See 'System.Random.randomR' for details.
+  getRandomR :: Random.Random a => (a, a) -> m a
 
+  -- | The same as 'getRandomR', but using a default range determined by the type:
+  --
+  -- * For bounded types (instances of 'Bounded', such as 'Char'),
+  --   the range is normally the whole type.
+  --
+  -- * For fractional types, the range is normally the semi-closed interval
+  -- @[0,1)@.
+  --
+  -- * For 'Integer', the range is (arbitrarily) the range of 'Int'.
+  --
+  -- See 'System.Random.random' for details.
+  getRandom :: Random.Random a => m a
+
+  -- | Plural variant of 'getRandomR', producing an infinite list of
+  -- random values instead of returning a new generator.
+  --
+  -- See 'System.Random.randomRs' for details.
+  getRandomRs :: Random.Random a => (a, a) -> m [a]
+
+  -- | Plural variant of 'getRandom', producing an infinite list of
+  -- random values instead of returning a new generator.
+  --
+  -- See 'System.Random.randoms' for details.
+  getRandoms :: Random.Random a => m [a]
+
+instance MonadRandom IO where
+  getRandomR = Random.randomRIO
+  getRandom = Random.randomIO
+  getRandomRs lohi = liftM (Random.randomRs lohi) Random.newStdGen
+  getRandoms = liftM Random.randoms Random.newStdGen
+
+instance MonadRandom m => MonadRandom (ContT r m) where
+  getRandomR = lift . getRandomR
+  getRandom = lift getRandom
+  getRandomRs = lift . getRandomRs
+  getRandoms = lift getRandoms
+
+instance MonadRandom m => MonadRandom (ExceptT e m) where
+  getRandomR = lift . getRandomR
+  getRandom = lift getRandom
+  getRandomRs = lift . getRandomRs
+  getRandoms = lift getRandoms
+
+instance MonadRandom m => MonadRandom (IdentityT m) where
+  getRandomR = lift . getRandomR
+  getRandom = lift getRandom
+  getRandomRs = lift . getRandomRs
+  getRandoms = lift getRandoms
+
+instance MonadRandom m => MonadRandom (MaybeT m) where
+  getRandomR = lift . getRandomR
+  getRandom = lift getRandom
+  getRandomRs = lift . getRandomRs
+  getRandoms = lift getRandoms
+
+instance (Monoid w, MonadRandom m) => MonadRandom (LazyRWS.RWST r w s m) where
+  getRandomR = lift . getRandomR
+  getRandom = lift getRandom
+  getRandomRs = lift . getRandomRs
+  getRandoms = lift getRandoms
+
+instance (Monoid w, MonadRandom m) => MonadRandom (StrictRWS.RWST r w s m) where
+  getRandomR = lift . getRandomR
+  getRandom = lift getRandom
+  getRandomRs = lift . getRandomRs
+  getRandoms = lift getRandoms
+
+instance MonadRandom m => MonadRandom (ReaderT r m) where
+  getRandomR = lift . getRandomR
+  getRandom = lift getRandom
+  getRandomRs = lift . getRandomRs
+  getRandoms = lift getRandoms
+
+instance MonadRandom m => MonadRandom (LazyState.StateT s m) where
+  getRandomR = lift . getRandomR
+  getRandom = lift getRandom
+  getRandomRs = lift . getRandomRs
+  getRandoms = lift getRandoms
+
+instance MonadRandom m => MonadRandom (StrictState.StateT s m) where
+  getRandomR = lift . getRandomR
+  getRandom = lift getRandom
+  getRandomRs = lift . getRandomRs
+  getRandoms = lift getRandoms
+
+instance (MonadRandom m, Monoid w) => MonadRandom (LazyWriter.WriterT w m) where
+  getRandomR = lift . getRandomR
+  getRandom = lift getRandom
+  getRandomRs = lift . getRandomRs
+  getRandoms = lift getRandoms
+
+instance (MonadRandom m, Monoid w) => MonadRandom (StrictWriter.WriterT w m) where
+  getRandomR = lift . getRandomR
+  getRandom = lift getRandom
+  getRandomRs = lift . getRandomRs
+  getRandoms = lift getRandoms
+
+------------------------------------------------------------
+-- MonadSplit
+------------------------------------------------------------
+
+-- | The class 'MonadSplit' proivides a way to specify a random number
+--   generator that can be split into two new generators.
+--
+--   This class is not very useful in practice: typically, one cannot
+--   actually do anything with a generator.  It remains here to avoid
+--   breaking existing code unnecessarily.  For a more practically
+--   useful interface, see 'MonadInterleave'.
+class Monad m => MonadSplit g m | m -> g where
+  -- | The 'getSplit' operation allows one to obtain two distinct random number
+  -- generators.
+  --
+  -- See 'System.Random.split' for details.
+  getSplit :: m g
+
+instance MonadSplit Random.StdGen IO where
+  getSplit = Random.newStdGen
+
+instance MonadSplit g m => MonadSplit g (ContT r m) where
+  getSplit = lift getSplit
+
+instance MonadSplit g m => MonadSplit g (ExceptT e m) where
+  getSplit = lift getSplit
+
+instance MonadSplit g m => MonadSplit g (IdentityT m) where
+  getSplit = lift getSplit
+
+instance MonadSplit g m => MonadSplit g (MaybeT m) where
+  getSplit = lift getSplit
+
+instance (Monoid w, MonadSplit g m) => MonadSplit g (LazyRWS.RWST r w s m) where
+  getSplit = lift getSplit
+
+instance (Monoid w, MonadSplit g m) => MonadSplit g (StrictRWS.RWST r w s m) where
+  getSplit = lift getSplit
+
+instance MonadSplit g m => MonadSplit g (ReaderT r m) where
+  getSplit = lift getSplit
+
+instance MonadSplit g m => MonadSplit g (LazyState.StateT s m) where
+  getSplit = lift getSplit
+
+instance MonadSplit g m => MonadSplit g (StrictState.StateT s m) where
+  getSplit = lift getSplit
+
+instance (Monoid w, MonadSplit g m) => MonadSplit g (LazyWriter.WriterT w m) where
+  getSplit = lift getSplit
+
+instance (Monoid w, MonadSplit g m) => MonadSplit g (StrictWriter.WriterT w m) where
+  getSplit = lift getSplit
+
+------------------------------------------------------------
+-- MonadInterleave
+------------------------------------------------------------
+
+-- | The class 'MonadInterleave' proivides a convenient interface atop
+--   a 'split' operation on a random generator.
+class MonadRandom m => MonadInterleave m where
+  -- | If @x :: m a@ is a computation in some random monad, then
+  --   @interleave x@ works by splitting the generator, running @x@
+  --   using one half, and using the other half as the final generator
+  --   state of @interleave x@ (replacing whatever the final generator
+  --   state otherwise would have been).  This means that computation
+  --   needing random values which comes after @interleave x@ does not
+  --   necessarily depend on the computation of @x@.  For example:
+  --
+  --   > >>> evalRandIO $ snd <$> ((,) <$> undefined <*> getRandom)
+  --   > *** Exception: Prelude.undefined
+  --   > >>> evalRandIO $ snd <$> ((,) <$> interleave undefined <*> getRandom)
+  --   > 6192322188769041625
+  --
+  --   This can be used, for example, to allow random computations to
+  --   run in parallel, or to create lazy infinite structures of
+  --   random values.  In the example below, the infinite tree
+  --   @randTree@ cannot be evaluated lazily: even though it is cut
+  --   off at two levels deep by @hew 2@, the random value in the
+  --   right subtree still depends on generation of all the random
+  --   values in the (infinite) left subtree, even though they are
+  --   ultimately unneeded.  Inserting a call to @interleave@, as in
+  --   @randTreeI@, solves the problem: the generator splits at each
+  --   @Node@, so random values in the left and right subtrees are
+  --   generated independently.
+  --
+  --   > data Tree = Leaf | Node Int Tree Tree deriving Show
+  --   >
+  --   > hew :: Int -> Tree -> Tree
+  --   > hew 0 _    = Leaf
+  --   > hew _ Leaf = Leaf
+  --   > hew n (Node x l r) = Node x (hew (n-1) l) (hew (n-1) r)
+  --   >
+  --   > randTree :: Rand StdGen Tree
+  --   > randTree = Node <$> getRandom <*> randTree <*> randTree
+  --   >
+  --   > randTreeI :: Rand StdGen Tree
+  --   > randTreeI = interleave $ Node <$> getRandom <*> randTreeI <*> randTreeI
+  --
+  --   > >>> hew 2 <$> evalRandIO randTree
+  --   > Node 2168685089479838995 (Node (-1040559818952481847) Leaf Leaf) (Node ^CInterrupted.
+  --   > >>> hew 2 <$> evalRandIO randTreeI
+  --   > Node 8243316398511136358 (Node 4139784028141790719 Leaf Leaf) (Node 4473998613878251948 Leaf Leaf)
+  interleave :: m a -> m a
+
+instance MonadInterleave m => MonadInterleave (ContT r m) where
+  interleave = mapContT interleave
+
+instance MonadInterleave m => MonadInterleave (ExceptT e m) where
+  interleave = mapExceptT interleave
+
+instance MonadInterleave m => MonadInterleave (IdentityT m) where
+  interleave = mapIdentityT interleave
+
+instance MonadInterleave m => MonadInterleave (MaybeT m) where
+  interleave = mapMaybeT interleave
+
+instance (Monoid w, MonadInterleave m) => MonadInterleave (LazyRWS.RWST r w s m) where
+  interleave = LazyRWS.mapRWST interleave
+
+instance (Monoid w, MonadInterleave m) => MonadInterleave (StrictRWS.RWST r w s m) where
+  interleave = StrictRWS.mapRWST interleave
+
+instance MonadInterleave m => MonadInterleave (ReaderT r m) where
+  interleave = mapReaderT interleave
+
+instance MonadInterleave m => MonadInterleave (LazyState.StateT s m) where
+  interleave = LazyState.mapStateT interleave
+
+instance MonadInterleave m => MonadInterleave (StrictState.StateT s m) where
+  interleave = StrictState.mapStateT interleave
+
+instance (Monoid w, MonadInterleave m) => MonadInterleave (LazyWriter.WriterT w m) where
+  interleave = LazyWriter.mapWriterT interleave
+
+instance (Monoid w, MonadInterleave m) => MonadInterleave (StrictWriter.WriterT w m) where
+  interleave = StrictWriter.mapWriterT interleave
+
+------------------------------------------------------------
+-- Convenience samplers
+------------------------------------------------------------
+
+-- | Sample a random value from a weighted nonempty collection of
+--   elements.  Crashes with a call to @error@ if the collection is
+--   empty or the total weight is zero.
+weighted :: (F.Foldable t, MonadRandom m) => t (a, Rational) -> m a
+weighted t = do
+  ma <- weightedMay t
+  case ma of
+    Nothing -> error "Control.Monad.Random.Class.weighted: empty collection, or total weight <= 0"
+    Just a -> return a
+
+-- | Sample a random value from a weighted collection of elements.
+--   Returns @Nothing@ if the collection is empty or the total weight is
+--   zero.
+weightedMay :: (F.Foldable t, MonadRandom m) => t (a, Rational) -> m (Maybe a)
+weightedMay = fromListMay . F.toList
+
+-- | Sample a random value from a weighted list.  The list must be
+--   non-empty and the total weight must be non-zero.
+fromList :: MonadRandom m => [(a, Rational)] -> m a
+fromList ws = do
+  ma <- fromListMay ws
+  case ma of
+    Nothing -> error "Control.Monad.Random.Class.fromList: empty list, or total weight = 0"
+    Just a -> return a
+
+-- | Sample a random value from a weighted list.  Return @Nothing@ if
+--   the list is empty or the total weight is nonpositive.
+fromListMay :: MonadRandom m => [(a, Rational)] -> m (Maybe a)
+fromListMay xs = do
+  let s = sum (map snd xs)
+      cums = scanl1 (\ ~(_, q) ~(y, s') -> (y, s' + q)) xs
+  if s <= 0
+    then return Nothing
+    else do
+      -- Pick a Word64 value uniformly
+      w <- getRandom
+      -- w / maxBound gives a uniform Rational in the range [0,1].
+      -- Subtract from 1 to match the way uniform Double values are
+      -- generated, and hence match the old behavior of this function.
+      let p = s * (1 - toRational (w :: Word64) / toRational (maxBound :: Word64))
+      return . fmap fst . F.find ((>= p) . snd) $ cums
+
+-- | Sample a value uniformly from a nonempty collection of elements.
+uniform :: (F.Foldable t, MonadRandom m) => t a -> m a
+uniform t = do
+  ma <- uniformMay t
+  case ma of
+    Nothing -> error "Control.Monad.Random.Class.uniform: empty collection"
+    Just a -> return a
+
+-- | Sample a value uniformly from a collection of elements.  Return
+--   @Nothing@ if the collection is empty.
+uniformMay :: (F.Foldable t, MonadRandom m) => t a -> m (Maybe a)
+uniformMay = fromListMay . map (flip (,) 1) . F.toList
+
+------------------------------------------------------------
+
+-- The old implementation of `fromListMay`, for comparison.  See
+-- https://github.com/byorgey/MonadRandom/issues/53 and
+-- https://byorgey.github.io/blog/posts/2024/10/14/MonadRandom-version-bump.html
+_fromListMayOld :: MonadRandom m => [(a, Rational)] -> m (Maybe a)
+_fromListMayOld xs = do
+  let s = fromRational (sum (map snd xs)) :: Double
+      cums = scanl1 (\ ~(_, q) ~(y, s') -> (y, s' + q)) xs
+  if s <= 0
+    then return Nothing
+    else do
+      p <- liftM toRational $ getRandomR (0, s)
+      return . fmap fst . F.find ((>= p) . snd) $ cums
diff --git a/Control/Monad/Random/Lazy.hs b/Control/Monad/Random/Lazy.hs
new file mode 100644
--- /dev/null
+++ b/Control/Monad/Random/Lazy.hs
@@ -0,0 +1,61 @@
+{-# LANGUAGE Safe #-}
+
+{- |
+Module       :  Control.Monad.Random.Lazy
+Copyright    :  (c) Brent Yorgey 2016
+License      :  BSD3 (see LICENSE)
+
+Maintainer   :  byorgey@gmail.com
+Stability    :  experimental
+Portability  :  non-portable (multi-param classes, functional dependencies, undecidable instances)
+
+Random monads that are lazy in the generator state. For a strict
+version, see "Control.Monad.Random.Strict", which has the same
+interface.
+-}
+
+module Control.Monad.Random.Lazy
+    ( -- * The Rand monad
+      Rand,
+      liftRand,
+      runRand,
+      evalRand,
+      execRand,
+      mapRand,
+      withRand,
+      evalRandIO,
+
+      -- * The RandT monad transformer
+      RandT,
+      liftRandT,
+      runRandT,
+      evalRandT,
+      execRandT,
+      mapRandT,
+      withRandT,
+      evalRandTIO,
+
+      -- * Some convenience re-exports
+
+      module System.Random,
+      module Control.Monad.Random.Class,
+      module Control.Monad,
+      module Control.Monad.Fix,
+      module Control.Monad.Trans,
+    ) where
+
+import           System.Random hiding (uniform, uniformR)
+
+import           Control.Monad.Random.Class
+
+import           Control.Monad.Trans
+import           Control.Monad.Trans.Random.Lazy (Rand, RandT, evalRand,
+                                                  evalRandIO, evalRandT,
+                                                  evalRandTIO, execRand,
+                                                  execRandT, liftRand,
+                                                  liftRandT, mapRand, mapRandT,
+                                                  runRand, runRandT, withRand,
+                                                  withRandT)
+
+import           Control.Monad
+import           Control.Monad.Fix
diff --git a/Control/Monad/Random/Strict.hs b/Control/Monad/Random/Strict.hs
new file mode 100644
--- /dev/null
+++ b/Control/Monad/Random/Strict.hs
@@ -0,0 +1,59 @@
+{-# LANGUAGE Safe #-}
+
+{- |
+Module       :  Control.Monad.Random.Strict
+Copyright    :  (c) Brent Yorgey 2016
+License      :  BSD3 (see LICENSE)
+
+Maintainer   :  byorgey@gmail.com
+Stability    :  experimental
+Portability  :  non-portable (multi-param classes, functional dependencies, undecidable instances)
+
+Random monads that are strict in the generator state.  For a lazy
+version, see "Control.Monad.Random.Lazy", which has the same
+interface.
+-}
+
+module Control.Monad.Random.Strict
+    ( -- * The Rand monad transformer
+      Rand,
+      liftRand,
+      runRand,
+      evalRand,
+      execRand,
+      mapRand,
+      withRand,
+      evalRandIO,
+      -- * The RandT monad transformer
+      RandT,
+      liftRandT,
+      runRandT,
+      evalRandT,
+      execRandT,
+      mapRandT,
+      withRandT,
+      evalRandTIO,
+      -- * Some convenience re-exports
+
+      module System.Random,
+      module Control.Monad.Random.Class,
+      module Control.Monad,
+      module Control.Monad.Fix,
+      module Control.Monad.Trans,
+    ) where
+
+import           System.Random hiding (uniform, uniformR)
+
+import           Control.Monad.Random.Class
+
+import           Control.Monad.Trans
+import           Control.Monad.Trans.Random.Strict (Rand, RandT, evalRand,
+                                                    evalRandIO, evalRandT,
+                                                    evalRandTIO, execRand,
+                                                    execRandT, liftRand,
+                                                    liftRandT, mapRand,
+                                                    mapRandT, runRand, runRandT,
+                                                    withRand, withRandT)
+
+import           Control.Monad
+import           Control.Monad.Fix
diff --git a/Control/Monad/Trans/Random.hs b/Control/Monad/Trans/Random.hs
new file mode 100644
--- /dev/null
+++ b/Control/Monad/Trans/Random.hs
@@ -0,0 +1,22 @@
+{-# LANGUAGE Safe #-}
+
+{- |
+Module       :  Control.Monad.Trans.Random
+Copyright    :  (c) Brent Yorgey 2016
+License      :  BSD3 (see LICENSE)
+
+Maintainer   :  byorgey@gmail.com
+Stability    :  experimental
+Portability  :  non-portable (multi-param classes, functional dependencies, undecidable instances)
+
+Random monads, passing a random number generator through a computation.
+
+This version is lazy; for a strict version, see
+"Control.Monad.Trans.Random.Strict", which has the same interface.
+-}
+
+module Control.Monad.Trans.Random
+    ( module Control.Monad.Trans.Random.Lazy,
+    ) where
+
+import           Control.Monad.Trans.Random.Lazy
diff --git a/Control/Monad/Trans/Random/Lazy.hs b/Control/Monad/Trans/Random/Lazy.hs
new file mode 100644
--- /dev/null
+++ b/Control/Monad/Trans/Random/Lazy.hs
@@ -0,0 +1,353 @@
+{-# LANGUAGE CPP                        #-}
+{-# LANGUAGE FlexibleInstances          #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE MultiParamTypeClasses      #-}
+{-# LANGUAGE Trustworthy                #-}
+{-# LANGUAGE TypeFamilies               #-}
+{-# LANGUAGE UndecidableInstances       #-}
+
+{- |
+Module       :  Control.Monad.Trans.Random.Lazy
+Copyright    :  (c) Brent Yorgey 2016
+License      :  BSD3 (see LICENSE)
+
+Maintainer   :  byorgey@gmail.com
+Stability    :  experimental
+Portability  :  non-portable (multi-param classes, functional dependencies, undecidable instances)
+
+Lazy random monads, passing a random number generator through a computation.
+See below for examples.
+
+For a strict version with the same interface, see
+"Control.Monad.Trans.Random.Strict".
+-}
+
+module Control.Monad.Trans.Random.Lazy
+  ( -- * The Rand monad transformer
+    Rand,
+    liftRand,
+    runRand,
+    evalRand,
+    execRand,
+    mapRand,
+    withRand,
+    evalRandIO,
+    -- * The RandT monad transformer
+    RandT,
+    liftRandT,
+    runRandT,
+    evalRandT,
+    execRandT,
+    mapRandT,
+    withRandT,
+    -- * Lifting other operations
+    liftCallCC,
+    liftCallCC',
+    liftCatch,
+    liftListen,
+    liftPass,
+    evalRandTIO,
+    -- * StatefulGen interface
+    RandGen(..),
+    withRandGen,
+    withRandGen_,
+    -- * Examples
+    -- ** Random monads
+    -- $examples
+  ) where
+
+import Control.Applicative ( Alternative )
+import Control.Arrow (first)
+import Control.Monad ( liftM, MonadPlus )
+import Control.Monad.Cont.Class (MonadCont(..))
+import Control.Monad.Error.Class ( MonadError(..) )
+import qualified Control.Monad.Fail as Fail
+import Control.Monad.Fix ( MonadFix )
+import Control.Monad.IO.Class ( MonadIO(..) )
+import Control.Monad.Primitive ( PrimMonad(..) )
+import Control.Monad.Random.Class ( MonadInterleave(..), MonadSplit(..), MonadRandom(..) )
+import Control.Monad.RWS.Class ( MonadState(..), MonadRWS, MonadReader, MonadWriter )
+import Control.Monad.Signatures ( Listen, Pass, CallCC, Catch )
+import Control.Monad.Trans.Class ( MonadTrans(..) )
+import qualified Control.Monad.Trans.State.Lazy as LazyState
+import Control.Monad.Trans.Random.Strict (RandGen(..))
+import Data.Functor.Identity ( Identity(runIdentity) )
+#if MIN_VERSION_random(1,2,0)
+import           System.Random.Stateful
+#else
+import           System.Random
+#endif
+
+-- | A random monad parameterized by the type @g@ of the generator to carry.
+--
+-- The 'return' function leaves the generator unchanged, while '>>=' uses the
+-- final generator of the first computation as the initial generator of the
+-- second.
+type Rand g = RandT g Identity
+
+-- | Construct a random monad computation from a function.
+-- (The inverse of 'runRand'.)
+liftRand
+  :: (g -> (a, g))
+  -- ^ pure random transformer
+  -> Rand g a
+  -- ^ equivalent generator-passing computation
+liftRand = RandT . state
+
+-- | Unwrap a random monad computation as a function.
+-- (The inverse of 'liftRand'.)
+runRand
+  :: Rand g a
+  -- ^ generator-passing computation to execute
+  -> g
+  -- ^ initial generator
+  -> (a, g)
+  -- ^ return value and final generator
+runRand t = runIdentity . runRandT t
+
+-- | Evaluate a random computation with the given initial generator and return
+-- the final value, discarding the final generator.
+--
+-- * @'evalRand' m s = fst ('runRand' m s)@
+evalRand
+  :: Rand g a
+  -- ^ generator-passing computation to execute
+  -> g
+  -- ^ initial generator
+  -> a
+  -- ^ return value of the random computation
+evalRand t = runIdentity . evalRandT t
+
+-- | Evaluate a random computation with the given initial generator and return
+-- the final generator, discarding the final value.
+--
+-- * @'execRand' m s = snd ('runRand' m s)@
+execRand
+  :: Rand g a
+  -- ^ generator-passing computation to execute
+  -> g
+  -- ^ initial generator
+  -> g
+  -- ^ final generator
+execRand t = runIdentity . execRandT t
+
+-- | Map both the return value and final generator of a computation using the
+-- given function.
+--
+-- * @'runRand' ('mapRand' f m) = f . 'runRand' m@
+mapRand :: ((a, g) -> (b, g)) -> Rand g a -> Rand g b
+mapRand f = mapRandT (liftM f)
+
+-- | @'withRand' f m@ executes action @m@ on a generator modified by applying @f@.
+--
+-- * @'withRand' f m = 'modify' f >> m@
+withRand :: (g -> g) -> Rand g a -> Rand g a
+withRand = withRandT
+
+-- | A random transformer monad parameterized by:
+--
+-- * @g@ - The generator.
+--
+-- * @m@ - The inner monad.
+--
+-- The 'return' function leaves the generator unchanged, while '>>=' uses the
+-- final generator of the first computation as the initial generator of the
+-- second.
+newtype RandT g m a = RandT { unRandT :: LazyState.StateT g m a }
+  deriving (Functor, Applicative, Alternative, Monad, MonadPlus, MonadTrans, MonadIO, MonadFix, MonadReader r, MonadWriter w)
+
+-- | Construct a random monad computation from an impure function.
+-- (The inverse of 'runRandT'.)
+liftRandT
+  :: (g -> m (a, g))
+  -- ^ impure random transformer
+  -> RandT g m a
+  -- ^ equivalent generator-passing computation
+liftRandT = RandT . LazyState.StateT
+
+-- | Unwrap a random monad computation as an impure function.
+-- (The inverse of 'liftRandT'.)
+runRandT
+  :: RandT g m a
+  -- ^ generator-passing computation to execute
+  -> g
+  -- ^ initial generator
+  -> m (a, g)
+  -- ^ return value and final generator
+runRandT = LazyState.runStateT . unRandT
+
+-- | Evaluate a random computation with the given initial generator and return
+-- the final value, discarding the final generator.
+--
+-- * @'evalRandT' m g = liftM fst ('runRandT' m g)@
+evalRandT :: (Monad m) => RandT g m a -> g -> m a
+evalRandT = LazyState.evalStateT . unRandT
+
+-- | Evaluate a random computation with the given initial generator and return
+-- the final generator, discarding the final value.
+--
+-- * @'execRandT' m g = liftM snd ('runRandT' m g)@
+execRandT :: (Monad m) => RandT g m a -> g -> m g
+execRandT = LazyState.execStateT . unRandT
+
+-- | Map both the return value and final generator of a computation using the
+-- given function.
+--
+-- * @'runRandT' ('mapRandT' f m) = f . 'runRandT' m@
+mapRandT :: (m (a, g) -> n (b, g)) -> RandT g m a -> RandT g n b
+mapRandT f = RandT . LazyState.mapStateT f . unRandT
+
+-- | @'withRandT' f m@ executes action @m@ on a generator modified by applying @f@.
+--
+-- * @'withRandT' f m = 'modify' f >> m@
+withRandT :: (g -> g) -> RandT g m a -> RandT g m a
+withRandT f = RandT . LazyState.withStateT f . unRandT
+
+instance (MonadCont m) => MonadCont (RandT g m) where
+  callCC = liftCallCC' callCC
+
+instance (MonadError e m) => MonadError e (RandT g m) where
+  throwError = lift . throwError
+  catchError = liftCatch catchError
+
+instance (MonadReader r m, MonadWriter w m, MonadState s m) => MonadRWS r w s (RandT g m)
+
+instance (RandomGen g, Monad m) => MonadRandom (RandT g m) where
+  getRandomR lohi = RandT . state $ randomR lohi
+  getRandom = RandT . state $ random
+  getRandomRs lohi = RandT . state $ first (randomRs lohi) . split
+  getRandoms = RandT . state $ first randoms . split
+
+instance (RandomGen g, Monad m) => MonadSplit g (RandT g m) where
+  getSplit = RandT . state $ split
+
+instance (Monad m, RandomGen g) => MonadInterleave (RandT g m) where
+  interleave (RandT m) = liftRandT $ \g -> case split g of
+    (gl, gr) -> liftM (\p -> (fst p, gr)) $ LazyState.runStateT m gl
+
+instance (MonadState s m) => MonadState s (RandT g m) where
+  get = lift get
+  put = lift . put
+
+instance PrimMonad m => PrimMonad (RandT s m) where
+  type PrimState (RandT s m) = PrimState m
+  primitive = lift . primitive
+
+instance Fail.MonadFail m => Fail.MonadFail (RandT g m) where
+  fail = lift . Fail.fail
+
+-- | Uniform lifting of a @callCC@ operation to the new monad.
+-- This version rolls back to the original state on entering the
+-- continuation.
+liftCallCC :: CallCC m (a, g) (b, g) -> CallCC (RandT g m) a b
+liftCallCC callCC_ f = RandT $ LazyState.liftCallCC callCC_ $ \c -> unRandT (f (RandT . c))
+
+-- | In-situ lifting of a @callCC@ operation to the new monad.
+-- This version uses the current state on entering the continuation.
+-- It does not satisfy the uniformity property (see "Control.Monad.Signatures").
+liftCallCC' :: CallCC m (a, g) (b, g) -> CallCC (RandT g m) a b
+liftCallCC' callCC_ f = RandT $ LazyState.liftCallCC' callCC_ $ \c -> unRandT (f (RandT . c))
+
+-- | Lift a @catchE@ operation to the new monad.
+liftCatch :: Catch e m (a, g) -> Catch e (RandT g m) a
+liftCatch catchE_ m f = RandT $ LazyState.liftCatch catchE_ (unRandT m) (unRandT . f)
+
+-- | Lift a @listen@ operation to the new monad.
+liftListen :: (Monad m) => Listen w m (a, g) -> Listen w (RandT g m) a
+liftListen listen_ m = RandT $ LazyState.liftListen listen_ (unRandT m)
+
+-- | Lift a @pass@ operation to the new monad.
+liftPass :: (Monad m) => Pass w m (a, g) -> Pass w (RandT g m) a
+liftPass pass_ m = RandT $ LazyState.liftPass pass_ (unRandT m)
+
+-- | Evaluate a random computation in the `IO` monad, splitting the global
+-- standard generator to get a new one for the computation.
+evalRandIO :: Rand StdGen a -> IO a
+evalRandIO t = liftM (evalRand t) newStdGen
+
+-- | Evaluate a random computation that is embedded in the `IO` monad,
+-- splitting the global standard generator to get a new one for the
+-- computation.
+evalRandTIO :: (MonadIO m) => RandT StdGen m a -> m a
+evalRandTIO t = liftIO newStdGen >>= evalRandT t
+
+#if MIN_VERSION_random(1,2,0)
+-- |
+--
+-- @since 0.5.3
+instance (Monad m, RandomGen g) => StatefulGen (RandGen g) (RandT g m) where
+  uniformWord32R r = applyRandT (genWord32R r)
+  uniformWord64R r = applyRandT (genWord64R r)
+  uniformWord8 = applyRandT genWord8
+  uniformWord16 = applyRandT genWord16
+  uniformWord32 = applyRandT genWord32
+  uniformWord64 = applyRandT genWord64
+#if MIN_VERSION_random(1,3,0)
+  uniformByteArrayM pinned sz = applyRandT $ uniformByteArray pinned sz
+#else
+  uniformShortByteString n = applyRandT (genShortByteString n)
+#endif
+
+-- |
+--
+-- @since 0.5.3
+instance (Monad m, RandomGen g) => RandomGenM (RandGen g) g (RandT g m) where
+  applyRandomGenM = applyRandT
+
+applyRandT :: Applicative m => (g -> (a, g)) -> RandGen g -> RandT g m a
+applyRandT f _ = liftRandT (pure . f)
+#endif
+
+-- | A `RandT` runner that allows using it with `StatefulGen` restricted actions. Returns
+-- the outcome of random computation and the new pseudo-random-number generator
+--
+-- >>> withRandGen (mkStdGen 2021) uniformM :: IO (Int, StdGen)
+-- (6070831465987696718,StdGen {unStdGen = SMGen 4687568268719557181 4805600293067301895})
+--
+-- @since 0.5.3
+withRandGen ::
+     g
+  -- ^ initial generator
+  -> (RandGen g -> RandT g m a)
+  -> m (a, g)
+  -- ^ return value and final generator
+withRandGen g action = runRandT (action RandGen) g
+
+-- | Same as `withRandGen`, but discards the resulting generator.
+--
+-- >>> withRandGen_ (mkStdGen 2021) uniformM :: IO Int
+-- 6070831465987696718
+--
+-- @since 0.5.3
+withRandGen_ ::
+     Monad m
+  => g
+  -- ^ initial generator
+  -> (RandGen g -> RandT g m a)
+  -> m a
+  -- ^ return value and final generator
+withRandGen_ g action = evalRandT (action RandGen) g
+
+
+{- $examples
+
+The @die@ function simulates the roll of a die, picking a number between 1
+and 6, inclusive, and returning it in the 'Rand' monad transformer.  Notice
+that this code will work with any random number generator @g@.
+
+> die :: (RandomGen g) => Rand g Int
+> die = getRandomR (1, 6)
+
+The @dice@ function uses @replicate@ and @sequence@ to simulate the roll of
+@n@ dice.
+
+> dice :: (RandomGen g) => Int -> Rand g [Int]
+> dice n = sequence (replicate n die)
+
+To extract a value from the 'Rand' monad transformer, we can use 'evalRandIO'.
+
+> main = do
+>   values <- evalRandIO (dice 2)
+>   putStrLn (show values)
+
+-}
diff --git a/Control/Monad/Trans/Random/Strict.hs b/Control/Monad/Trans/Random/Strict.hs
new file mode 100644
--- /dev/null
+++ b/Control/Monad/Trans/Random/Strict.hs
@@ -0,0 +1,360 @@
+{-# LANGUAGE CPP                        #-}
+{-# LANGUAGE FlexibleInstances          #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE MultiParamTypeClasses      #-}
+{-# LANGUAGE Trustworthy                #-}
+{-# LANGUAGE TypeFamilies               #-}
+{-# LANGUAGE UndecidableInstances       #-}
+
+{- |
+Module       :  Control.Monad.Trans.Random.Strict
+Copyright    :  (c) Brent Yorgey 2016
+License      :  BSD3 (see LICENSE)
+
+Maintainer   :  byorgey@gmail.com
+Stability    :  experimental
+Portability  :  non-portable (multi-param classes, functional dependencies, undecidable instances)
+
+Strict random monads, passing a random number generator through a computation.
+See below for examples.
+
+In this version, sequencing of computations is strict (but computations are not
+strict in the state unless you force it with seq or the like). For a lazy
+version with the same interface, see "Control.Monad.Trans.Random.Lazy".
+-}
+
+module Control.Monad.Trans.Random.Strict
+  ( -- * The Rand monad transformer
+    Rand,
+    liftRand,
+    runRand,
+    evalRand,
+    execRand,
+    mapRand,
+    withRand,
+    evalRandIO,
+    -- * The RandT monad transformer
+    RandT,
+    liftRandT,
+    runRandT,
+    evalRandT,
+    execRandT,
+    mapRandT,
+    withRandT,
+    evalRandTIO,
+    -- * Lifting other operations
+    liftCallCC,
+    liftCallCC',
+    liftCatch,
+    liftListen,
+    liftPass,
+    -- * StatefulGen interface
+    RandGen(..),
+    withRandGen,
+    withRandGen_,
+    -- * Examples
+    -- ** Random monads
+    -- $examples
+  ) where
+
+import Control.Applicative ( Alternative )
+import Control.Arrow (first)
+import Control.Monad ( liftM, MonadPlus )
+import Control.Monad.Cont.Class (MonadCont(..))
+import Control.Monad.Error.Class ( MonadError(..) )
+import qualified Control.Monad.Fail               as Fail
+import Control.Monad.Fix ( MonadFix )
+import Control.Monad.IO.Class ( MonadIO(..) )
+import Control.Monad.Primitive ( PrimMonad(..) )
+import Control.Monad.Random.Class ( MonadInterleave(..), MonadSplit(..), MonadRandom(..) )
+import Control.Monad.RWS.Class ( MonadState(..), MonadRWS, MonadReader, MonadWriter )
+import Control.Monad.Signatures ( Listen, Pass, CallCC, Catch )
+import Control.Monad.Trans.Class ( MonadTrans(..) )
+import qualified Control.Monad.Trans.State.Strict as StrictState
+import Data.Functor.Identity ( Identity(runIdentity) )
+#if MIN_VERSION_random(1,2,0)
+import           System.Random.Stateful
+#else
+import           System.Random
+#endif
+
+-- | A random monad parameterized by the type @g@ of the generator to carry.
+--
+-- The 'return' function leaves the generator unchanged, while '>>=' uses the
+-- final generator of the first computation as the initial generator of the
+-- second.
+type Rand g = RandT g Identity
+
+-- | Construct a random monad computation from a function.
+-- (The inverse of 'runRand'.)
+liftRand
+  :: (g -> (a, g))
+  -- ^ pure random transformer
+  -> Rand g a
+  -- ^ equivalent generator-passing computation
+liftRand = RandT . state
+
+-- | Unwrap a random monad computation as a function.
+-- (The inverse of 'liftRand'.)
+runRand
+  :: Rand g a
+  -- ^ generator-passing computation to execute
+  -> g
+  -- ^ initial generator
+  -> (a, g)
+  -- ^ return value and final generator
+runRand t = runIdentity . runRandT t
+
+-- | Evaluate a random computation with the given initial generator and return
+-- the final value, discarding the final generator.
+--
+-- * @'evalRand' m s = fst ('runRand' m s)@
+evalRand
+  :: Rand g a
+  -- ^ generator-passing computation to execute
+  -> g
+  -- ^ initial generator
+  -> a
+  -- ^ return value of the random computation
+evalRand t = runIdentity . evalRandT t
+
+-- | Evaluate a random computation with the given initial generator and return
+-- the final generator, discarding the final value.
+--
+-- * @'execRand' m s = snd ('runRand' m s)@
+execRand
+  :: Rand g a
+  -- ^ generator-passing computation to execute
+  -> g
+  -- ^ initial generator
+  -> g
+  -- ^ final generator
+execRand t = runIdentity . execRandT t
+
+-- | Map both the return value and final generator of a computation using the
+-- given function.
+--
+-- * @'runRand' ('mapRand' f m) = f . 'runRand' m@
+mapRand :: ((a, g) -> (b, g)) -> Rand g a -> Rand g b
+mapRand f = mapRandT (liftM f)
+
+-- | @'withRand' f m@ executes action @m@ on a generator modified by applying @f@.
+--
+-- * @'withRand' f m = 'modify' f >> m@
+withRand :: (g -> g) -> Rand g a -> Rand g a
+withRand = withRandT
+
+-- | A random transformer monad parameterized by:
+--
+-- * @g@ - The generator.
+--
+-- * @m@ - The inner monad.
+--
+-- The 'return' function leaves the generator unchanged, while '>>=' uses the
+-- final generator of the first computation as the initial generator of the
+-- second.
+newtype RandT g m a = RandT { unRandT :: StrictState.StateT g m a }
+  deriving (Functor, Applicative, Alternative, Monad, MonadPlus, MonadTrans, MonadIO, MonadFix, MonadReader r, MonadWriter w)
+
+-- | Construct a random monad computation from an impure function.
+-- (The inverse of 'runRandT'.)
+liftRandT
+  :: (g -> m (a, g))
+  -- ^ impure random transformer
+  -> RandT g m a
+  -- ^ equivalent generator-passing computation
+liftRandT = RandT . StrictState.StateT
+
+-- | Unwrap a random monad computation as an impure function.
+-- (The inverse of 'liftRandT'.)
+runRandT
+  :: RandT g m a
+  -- ^ generator-passing computation to execute
+  -> g
+  -- ^ initial generator
+  -> m (a, g)
+  -- ^ return value and final generator
+runRandT = StrictState.runStateT . unRandT
+
+-- | Evaluate a random computation with the given initial generator and return
+-- the final value, discarding the final generator.
+--
+-- * @'evalRandT' m g = liftM fst ('runRandT' m g)@
+evalRandT :: (Monad m) => RandT g m a -> g -> m a
+evalRandT = StrictState.evalStateT . unRandT
+
+-- | Evaluate a random computation with the given initial generator and return
+-- the final generator, discarding the final value.
+--
+-- * @'execRandT' m g = liftM snd ('runRandT' m g)@
+execRandT :: (Monad m) => RandT g m a -> g -> m g
+execRandT = StrictState.execStateT . unRandT
+
+-- | Map both the return value and final generator of a computation using the
+-- given function.
+--
+-- * @'runRandT' ('mapRandT' f m) = f . 'runRandT' m@
+mapRandT :: (m (a, g) -> n (b, g)) -> RandT g m a -> RandT g n b
+mapRandT f = RandT . StrictState.mapStateT f . unRandT
+
+-- | @'withRandT' f m@ executes action @m@ on a generator modified by applying @f@.
+--
+-- * @'withRandT' f m = 'modify' f >> m@
+withRandT :: (g -> g) -> RandT g m a -> RandT g m a
+withRandT f = RandT . StrictState.withStateT f . unRandT
+
+instance (MonadCont m) => MonadCont (RandT g m) where
+  callCC = liftCallCC' callCC
+
+instance (MonadError e m) => MonadError e (RandT g m) where
+  throwError = lift . throwError
+  catchError = liftCatch catchError
+
+instance (MonadReader r m, MonadWriter w m, MonadState s m) => MonadRWS r w s (RandT g m)
+
+instance (RandomGen g, Monad m) => MonadRandom (RandT g m) where
+  getRandomR lohi = RandT . state $ randomR lohi
+  getRandom = RandT . state $ random
+  getRandomRs lohi = RandT . state $ first (randomRs lohi) . split
+  getRandoms = RandT . state $ first randoms . split
+
+instance (RandomGen g, Monad m) => MonadSplit g (RandT g m) where
+  getSplit = RandT . state $ split
+
+instance (Monad m, RandomGen g) => MonadInterleave (RandT g m) where
+  interleave (RandT m) = liftRandT $ \g -> case split g of
+    (gl, gr) -> liftM (\p -> (fst p, gr)) $ StrictState.runStateT m gl
+
+instance (MonadState s m) => MonadState s (RandT g m) where
+  get = lift get
+  put = lift . put
+
+instance PrimMonad m => PrimMonad (RandT s m) where
+  type PrimState (RandT s m) = PrimState m
+  primitive = lift . primitive
+
+instance Fail.MonadFail m => Fail.MonadFail (RandT g m) where
+  fail = lift . Fail.fail
+
+-- | Uniform lifting of a @callCC@ operation to the new monad.
+-- This version rolls back to the original state on entering the
+-- continuation.
+liftCallCC :: CallCC m (a, g) (b, g) -> CallCC (RandT g m) a b
+liftCallCC callCC_ f = RandT $ StrictState.liftCallCC callCC_ $ \c -> unRandT (f (RandT . c))
+
+-- | In-situ lifting of a @callCC@ operation to the new monad.
+-- This version uses the current state on entering the continuation.
+-- It does not satisfy the uniformity property (see "Control.Monad.Signatures").
+liftCallCC' :: CallCC m (a, g) (b, g) -> CallCC (RandT g m) a b
+liftCallCC' callCC_ f = RandT $ StrictState.liftCallCC' callCC_ $ \c -> unRandT (f (RandT . c))
+
+-- | Lift a @catchE@ operation to the new monad.
+liftCatch :: Catch e m (a, g) -> Catch e (RandT g m) a
+liftCatch catchE_ m f = RandT $ StrictState.liftCatch catchE_ (unRandT m) (unRandT . f)
+
+-- | Lift a @listen@ operation to the new monad.
+liftListen :: (Monad m) => Listen w m (a, g) -> Listen w (RandT g m) a
+liftListen listen_ m = RandT $ StrictState.liftListen listen_ (unRandT m)
+
+-- | Lift a @pass@ operation to the new monad.
+liftPass :: (Monad m) => Pass w m (a, g) -> Pass w (RandT g m) a
+liftPass pass_ m = RandT $ StrictState.liftPass pass_ (unRandT m)
+
+-- | Evaluate a random computation in the `IO` monad, splitting the global
+-- standard generator to get a new one for the computation.
+evalRandIO :: Rand StdGen a -> IO a
+evalRandIO t = liftM (evalRand t) newStdGen
+
+-- | Evaluate a random computation that is embedded in the `IO` monad,
+-- splitting the global standard generator to get a new one for the
+-- computation.
+evalRandTIO :: (MonadIO m) => RandT StdGen m a -> m a
+evalRandTIO t = liftIO newStdGen >>= evalRandT t
+
+
+-- | A proxy that carries information about the type of generator to use with @RandT@
+-- monad and its `StatefulGen` instance.
+--
+-- @since 0.5.3
+data RandGen g = RandGen
+
+#if MIN_VERSION_random(1,2,0)
+-- |
+--
+-- @since 0.5.3
+instance (Monad m, RandomGen g) => StatefulGen (RandGen g) (RandT g m) where
+  uniformWord32R r = applyRandT (genWord32R r)
+  uniformWord64R r = applyRandT (genWord64R r)
+  uniformWord8 = applyRandT genWord8
+  uniformWord16 = applyRandT genWord16
+  uniformWord32 = applyRandT genWord32
+  uniformWord64 = applyRandT genWord64
+#if MIN_VERSION_random(1,3,0)
+  uniformByteArrayM pinned sz = applyRandT $ uniformByteArray pinned sz
+#else
+  uniformShortByteString n = applyRandT (genShortByteString n)
+#endif
+
+-- |
+--
+-- @since 0.5.3
+instance (Monad m, RandomGen g) => RandomGenM (RandGen g) g (RandT g m) where
+  applyRandomGenM = applyRandT
+
+applyRandT :: Applicative m => (g -> (a, g)) -> RandGen g -> RandT g m a
+applyRandT f _ = liftRandT (pure . f)
+#endif
+
+-- | A `RandT` runner that allows using it with `StatefulGen` restricted actions. Returns
+-- the outcome of random computation and the new pseudo-random-number generator
+--
+-- >>> withRandGen (mkStdGen 2021) uniformM :: IO (Int, StdGen)
+-- (6070831465987696718,StdGen {unStdGen = SMGen 4687568268719557181 4805600293067301895})
+--
+-- @since 0.5.3
+withRandGen ::
+     g
+  -- ^ initial generator
+  -> (RandGen g -> RandT g m a)
+  -> m (a, g)
+  -- ^ return value and final generator
+withRandGen g action = runRandT (action RandGen) g
+
+-- | Same as `withRandGen`, but discards the resulting generator.
+--
+-- >>> withRandGen_ (mkStdGen 2021) uniformM :: IO Int
+-- 6070831465987696718
+--
+-- @since 0.5.3
+withRandGen_ ::
+     Monad m
+  => g
+  -- ^ initial generator
+  -> (RandGen g -> RandT g m a)
+  -> m a
+  -- ^ return value and final generator
+withRandGen_ g action = evalRandT (action RandGen) g
+
+
+{- $examples
+
+The @die@ function simulates the roll of a die, picking a number between 1
+and 6, inclusive, and returning it in the 'Rand' monad transformer.  Notice
+that this code will work with any random number generator @g@.
+
+> die :: (RandomGen g) => Rand g Int
+> die = getRandomR (1, 6)
+
+The @dice@ function uses @replicate@ and @sequence@ to simulate the roll of
+@n@ dice.
+
+> dice :: (RandomGen g) => Int -> Rand g [Int]
+> dice n = sequence (replicate n die)
+
+To extract a value from the 'Rand' monad transformer, we can use 'evalRandIO'.
+
+> main = do
+>   values <- evalRandIO (dice 2)
+>   putStrLn (show values)
+
+-}
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,38 +1,34 @@
-MonadRandom library.
-Copyright 2006-2007 Cale Gibbard.  All rights reserved.
-Copyright 2006 Russell O'Connor, Dan Doel, Remi Turk.  All rights reserved.
-Copyright 2007 Eric Kidd.  All rights reserved.
-
-[This code was originally posted by Cale Gibbard to the Haskell Wiki,
-remnants of which can be seen at:
-
-http://web.archive.org/web/20070615071737/http://haskell.org/hawiki/MonadRandom
-
-This code was relicensed from a 2-clause BSD license to the license below
-by Cale Gibbard's statement at:
-
-http://www.haskell.org/haskellwiki/User:CaleGibbard
+Copyright (c) 2016, Brent Yorgey
 
-The code was then moved to:
+All rights reserved.
 
-http://www.haskell.org/haskellwiki/NewMonads/MonadRandom
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
 
-New additions by several people were provided under the implicit license at:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
 
-http://www.haskell.org/haskellwiki/HaskellWiki:Copyrights
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
 
-So, in theory, this license should apply to everything in this library.]
+    * Neither the name of Brent Yorgey nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
 
-Permission is hereby granted, free of charge, to any person obtaining this
-work (the "Work"), to deal in the Work without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Work, and to permit
-persons to whom the Work is furnished to do so.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-THE WORK IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF OR IN CONNECTION WITH THE WORK OR THE USE OR OTHER DEALINGS IN
-THE WORK.
+Previous versions of this package were distributed under the simple
+permissive license used on the Haskell Wiki; see OLD-LICENSE for
+details.
diff --git a/MonadRandom.cabal b/MonadRandom.cabal
--- a/MonadRandom.cabal
+++ b/MonadRandom.cabal
@@ -1,8 +1,8 @@
 name:                MonadRandom
-version:             0.3.0.2
+version:             0.6.2.1
 synopsis:            Random-number generation monad.
 description:         Support for computations which consume random values.
-license:             OtherLicense
+license:             BSD3
 license-file:        LICENSE
 author:              Cale Gibbard and others
 maintainer:          Brent Yorgey <byorgey@gmail.com>
@@ -11,12 +11,27 @@
 build-type:          Simple
 cabal-version:       >=1.10
 extra-source-files:  CHANGES.markdown
+tested-with:         GHC ==8.0.2 || ==8.2.2 || ==8.4.4 || ==8.6.5 || ==8.8.4 || ==8.10.7 || ==9.0.2 || ==9.2.8 || ==9.4.8 || ==9.6.6 || ==9.8.2 || ==9.10.1 || ==9.12.1 || ==9.14.1
+
 source-repository head
   type:     git
-  location: git://github.com/byorgey/MonadRandom.git
+  location: https://github.com/byorgey/MonadRandom
 
 library
-  exposed-modules:     Control.Monad.Random, Control.Monad.Random.Class
-  build-depends:       base >= 2 && < 5, transformers >= 0.3 && < 0.5, transformers-compat == 0.4.*, mtl, random
+  exposed-modules:
+    Control.Monad.Random,
+    Control.Monad.Random.Class,
+    Control.Monad.Random.Lazy,
+    Control.Monad.Random.Strict,
+    Control.Monad.Trans.Random,
+    Control.Monad.Trans.Random.Lazy,
+    Control.Monad.Trans.Random.Strict
+  build-depends:
+    base                >=4.8 && <5,
+    transformers        >=0.5 && <0.7,
+    mtl                 >=2.2.1 && <2.3 || >= 2.3.1 && < 2.4,
+    primitive           >=0.6 && <0.10,
+    random              >=1.0.1 && <1.4
   ghc-options:         -Wall
   default-language:    Haskell2010
+  other-extensions:    Safe
