random-fu- Random number generation



Random variables. An RVar is a sampleable random variable. Because probability distributions form a monad, they are quite easy to work with in the standard Haskell monadic styles. For examples, see the source for any of the Distribution instances - they all are defined in terms of RVars.



type RVar = RVarT IdentitySource


 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 a couple ways to sample RVars:

 sampleFrom DevRandom (uniform 1 100) :: IO Int
  • As a pure function transforming a functional RNG:

runRVar :: RandomSource m s => RVar a -> s -> m aSource


data RVarT m a Source



 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, and then it can be sampled as usual:

     rw <- rwalkIO
     x <- sampleFrom DevURandom rw
     y <- sampleFrom DevURandom rw


 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, but there is a gotcha lurking here: sample and runRVarT inherit the extreme generality of lift, so there will almost always need to be an explicit type signature lurking somewhere in any client code making use of RVarT with MTL types. In this example, the inferred type of start would be too general to be practical, so the signature for rwalk explicitly fixes it to Double. Alternatively, in this case sample could be replaced with \x -> runRVarTWith MTL.lift x StdRandom.

 rwalk count start gen = evalState (runStateT (sample (replicateM count rwalkState)) gen) start



The Lift context allows random variables to be defined using a minimal underlying functor (Identity is sufficient for "conventional" random variables) and then sampled in any monad into which the underlying functor can be embedded (which, for Identity, is all monads).


For non-standard liftings or those where you would rather not introduce a Lift instance, see runRVarTWith.


Like runRVarT but allowing a user-specified lift operation. This operation must obey the "monad transformer" laws:

 lift . return = return


 embedState get put = \m -> do
     s <- get
     put s
     return res