```{- |
Monadic functions for random number generation.

Because manually threading the correct 'Seed' value around is
tedious and error-prone, one common approach is to use some
kind of state monad to hide it. This module provides the
convenience functions to make this easy; just write a
'RandomM' instance for your particular monad, and then you
can easily and conveniently generate random numbers.
-}

(
-- * Random seed
Seed (),

-- * Random monads
RandomM (..),

-- * Monadic operations
bounded_randomM, unit_randomM, range_randomM,
)
where

import Random.MWC.Pure

{- |
The class of monads holding a single random 'Seed' within their
state.
-}
class Monad m => RandomM m where
-- | Fetch the current 'Seed' value.
get_random_seed :: m Seed

-- | Replace the current 'Seed' value.
set_random_seed :: Seed -> m ()

{- |
The monadic analogue of 'bounded_random'.

Return a value randomly chosen between 'minBound' and 'maxBound'.
Uses the current 'Seed' value from within the monad, automatically
updating said seed value in the process. Thus, repeatedly calling
this function will yield different successive values.
-}
bounded_randomM :: (RandomM m, BoundedRandom x) => m x
bounded_randomM = do
s0 <- get_random_seed
let (x, s1) = bounded_random s0
set_random_seed s1
return x

{- |
The monadic analogue of 'unit_random'.

Returns a value randomly chosen between \"zero\" and \"one\". Uses
the current 'Seed' value from within the monad, automatically
updating said seed value in the process. Thus, repeatedly calling
this function will yield different successive values.
-}
unit_randomM :: (RandomM m, UnitRandom x) => m x
unit_randomM = do
s0 <- get_random_seed
let (x, s1) = unit_random s0
set_random_seed s1
return x

{- |
The monadic analogue of 'range_random'.

Returns a value randomly chosen from a user-specified range
(inclusive). Uses the current 'Seed' value from within the monad,
automatically updating said seed value in the process. Thus,
repeatedly calling this function will yield different successive
values.
-}
range_randomM :: (RandomM m, RangeRandom x) => (x, x) -> m x
range_randomM xr = do
s0 <- get_random_seed
let (x, s1) = range_random xr s0
set_random_seed s1
return x
```