random-fu-0.3.0.1: Random number generation
Safe HaskellSafe-Inferred
LanguageHaskell2010

Data.Random.RVar

Synopsis

Documentation

type RVar = RVarT Identity #

An opaque type modeling a "random variable" - a value which depends on the outcome of some random event. RVars can be conveniently defined by an imperative-looking style:

normalPair =  do
    u <- stdUniform
    t <- stdUniform
    let r = sqrt (-2 * log u)
        theta = (2 * pi) * t

        x = r * cos theta
        y = r * sin theta
    return (x,y)

OR by a more applicative style:

logNormal = exp <$> stdNormal

Once defined (in any style), there are several ways to sample RVars:

  • Using an immutable pseudo-random number generator that has an instance for RandomGen with StateT monad:
>>> import qualified Data.Random as Fu (uniform)
>>> import System.Random (mkStdGen)
>>> import Control.Monad.State (runState)
>>> runState (sampleStateRVar (Fu.uniform 1 (100 :: Integer))) (mkStdGen 2021)
(79,StdGen {unStdGen = SMGen 4687568268719557181 4805600293067301895})
  • Using a mutable pseud-random number generator that has an instance for StatefulGen with ReaderT monad.
>>> import qualified Data.Random as Fu (uniform)
>>> import System.Random.MWC (create)
>>> import Control.Monad.Reader (runReaderT)
>>> import qualified Data.Vector.Storable as VS
>>> initialize (VS.singleton 2021) >>= runReaderT (sampleReaderRVar (uniform 1 (100 :: Integer)))
8

runRVar :: StatefulGen g m => RVar a -> g -> m a #

"Run" an RVar - samples the random variable from the provided source of entropy.

data RVarT (m :: Type -> Type) a #

A random variable with access to operations in an underlying monad. Useful examples include any form of state for implementing random processes with hysteresis, or writer monads for implementing tracing of complicated algorithms.

For example, a simple random walk can be implemented as an RVarT IO value:

rwalkIO :: IO (RVarT IO Double)
rwalkIO d = do
    lastVal <- newIORef 0

    let x = do
            prev    <- lift (readIORef lastVal)
            change  <- rvarT StdNormal

            let new = prev + change
            lift (writeIORef lastVal new)
            return new

    return x

To run the random walk it must first be initialized, after which it can be sampled as usual:

do
    rw <- rwalkIO
    x <- sampleRVarT rw
    y <- sampleRVarT rw
    ...

The same random-walk process as above can be implemented using MTL types as follows (using import Control.Monad.Trans as MTL):

rwalkState :: RVarT (State Double) Double
rwalkState = do
    prev <- MTL.lift get
    change  <- rvarT StdNormal

    let new = prev + change
    MTL.lift (put new)
    return new

Invocation is straightforward (although a bit noisy) if you're used to MTL:

rwalk :: Int -> Double -> StdGen -> ([Double], StdGen)
rwalk count start gen =
    flip evalState start .
        flip runStateT gen .
            sampleRVarTWith MTL.lift $
                replicateM count rwalkState

Instances

Instances details
MonadTrans RVarT 
Instance details

Defined in Data.RVar

Methods

lift :: Monad m => m a -> RVarT m a #

MonadPrompt Prim (RVarT n) 
Instance details

Defined in Data.RVar

Methods

prompt :: Prim a -> RVarT n a #

StatefulGen RGen (RVarT m) 
Instance details

Defined in Data.RVar

MonadIO m => MonadIO (RVarT m) 
Instance details

Defined in Data.RVar

Methods

liftIO :: IO a -> RVarT m a #

Applicative (RVarT n) 
Instance details

Defined in Data.RVar

Methods

pure :: a -> RVarT n a #

(<*>) :: RVarT n (a -> b) -> RVarT n a -> RVarT n b #

liftA2 :: (a -> b -> c) -> RVarT n a -> RVarT n b -> RVarT n c #

(*>) :: RVarT n a -> RVarT n b -> RVarT n b #

(<*) :: RVarT n a -> RVarT n b -> RVarT n a #

Functor (RVarT n) 
Instance details

Defined in Data.RVar

Methods

fmap :: (a -> b) -> RVarT n a -> RVarT n b #

(<$) :: a -> RVarT n b -> RVarT n a #

Monad (RVarT n) 
Instance details

Defined in Data.RVar

Methods

(>>=) :: RVarT n a -> (a -> RVarT n b) -> RVarT n b #

(>>) :: RVarT n a -> RVarT n b -> RVarT n b #

return :: a -> RVarT n a #

Lift m n => Sampleable (RVarT m) n t Source # 
Instance details

Defined in Data.Random.Sample

Methods

sampleFrom :: StatefulGen g n => g -> RVarT m t -> n t Source #

Lift (RVarT Identity) (RVarT m) Source # 
Instance details

Defined in Data.Random.Lift

Methods

lift :: RVarT Identity a -> RVarT m a Source #

runRVarT :: (Lift n m, StatefulGen g m) => RVarT n a -> g -> m a Source #

Like runRVarTWith, but using an implicit lifting (provided by the Lift class)

runRVarTWith :: forall m n g a. StatefulGen g m => (forall t. n t -> m t) -> RVarT n a -> g -> m a #

"Runs" an RVarT, sampling the random variable it defines.

The first argument lifts the base monad into the sampling monad. This operation must obey the "monad transformer" laws:

lift . return = return
lift (x >>= f) = (lift x) >>= (lift . f)

One example of a useful non-standard lifting would be one that takes State s to another monad with a different state representation (such as IO with the state mapped to an IORef):

embedState :: (Monad m) => m s -> (s -> m ()) -> State s a -> m a
embedState get put = \m -> do
    s <- get
    (res,s) <- return (runState m s)
    put s
    return res

The ability to lift is very important - without it, every RVar would have to either be given access to the full capability of the monad in which it will eventually be sampled (which, incidentally, would also have to be monomorphic so you couldn't sample one RVar in more than one monad) or functions manipulating RVars would have to use higher-ranked types to enforce the same kind of isolation and polymorphism.

data RGen #

Constructors

RGen 

uniformRVarT :: forall a (m :: Type -> Type). Uniform a => RVarT m a #

uniformRangeRVarT :: forall a (m :: Type -> Type). UniformRange a => (a, a) -> RVarT m a #