Uses the supplied function to get a value from the current global
random generator, and updates the global generator with the new generator
returned by the function. For example, rollDice produces a pseudo-random integer
between 1 and 6:
This is an outdated function and it is recommended to switch to its
equivalent applyAtomicGen instead, possibly with the
globalStdGen if relying on the global state is
acceptable.
This function is equivalent to getStdRandomrandom and is included in
this interface for historical reasons and backwards compatibility. It is
recommended to use uniformM instead, possibly with
the globalStdGen if relying on the global state is
acceptable.
A variant of randomRM that uses the global
pseudo-random number generator globalStdGen
Example1 expression
>>> randomRIO (2020, 2100) :: IO Int2028
Similar to randomIO, this function is equivalent to getStdRandomrandomR and is included in this interface for historical reasons and
backwards compatibility. It is recommended to use
uniformRM instead, possibly with the
globalStdGen if relying on the global state is
acceptable.
Offset into a mutable array from the beginning in number of bytes. Offset will be
clamped into the range between 0 and the total size of the mutable array
Fill in a slice of a mutable byte array with randomly generated bytes. This function
does not fail, instead it clamps the offset and number of bytes to generate into a valid
range.
Produce an infinite list of pseudo-random values in a specified range. Same as
uniforms, integrates nicely with list fusion. There is no way to recover the final
generator, therefore either use split before calling uniformRs or use
uniformListR instead.
Produce an infinite list of pseudo-random values. Integrates nicely with list
fusion. Naturally, there is no way to recover the final generator, therefore either use
split before calling uniforms or use uniformList instead.
Constructs a StdGen deterministically from a Word64 seed.
The difference between mkStdGen is that mkStdGen64 will work the same on 64-bit and
32-bit architectures, while the former can only use 32-bit of information for
initializing the psuedo-random number generator on 32-bit operating systems
Construct a Seed from a ByteArray of expected length. Whenever ByteArray does
not match the SeedSize specified by the pseudo-random generator, this function will
fail.
Helper function that allows for operating directly on the Seed, while supplying a
function that uses the pseudo-random number generator that is constructed from that
Seed.
Read the seed from a file and use it for constructing a pseudo-random number
generator. After supplied action has been applied to the constructed generator, the
resulting generator will be converted back to a seed and written to the same file.
The class of types for which random values can be generated. Most
instances of Random will produce values that are uniformly distributed on the full
range, but for those types without a well-defined "full range" some sensible default
subrange will be selected.
Random exists primarily for backwards compatibility with version 1.1 of
this library. In new code, use the better specified Uniform and
UniformRange instead.
Takes a range (lo,hi) and a pseudo-random number generator
g, and returns a pseudo-random value uniformly distributed over the
closed interval [lo,hi], together with a new generator. It is unspecified
what happens if lo>hi, but usually the values will simply get swapped.
Example3 expressions
>>> let gen = mkStdGen 26>>> fst $ randomR ('a', 'z') gen'z'>>> fst $ randomR ('a', 'z') gen'z'
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.
There is no requirement to follow the Ord instance and the concept of range can be
defined on per type basis. For example product types will treat their values
independently:
Returns an Int that is uniformly distributed over the range returned by
genRange (including both end points), and a new generator. Using next
is inefficient as all operations go via Integer. See
here for
more details. It is thus deprecated.
genShortByteString n g returns a ShortByteString of length n filled with
pseudo-random bytes.
Note - This function will be removed from the type class in the next major release as
it is no longer needed because of unsafeUniformFillMutableByteArray.
Fill in the supplied MutableByteArray with uniformly generated random bytes. This function
is unsafe because it is not required to do any bounds checking. For a safe variant use
System.Random.Sateful.uniformFillMutableByteArrayM instead.
Returns two distinct pseudo-random number generators.
Implementations should take care to ensure that the resulting generators
are not correlated. Some pseudo-random number generators are not
splittable. In that case, the split implementation should fail with a
descriptive error message.
Instances8RandomGen, …
RandomGenStdGenDefined in random-1.3.1 · System.Random.Internal
RandomGenSMGenDefined in random-1.3.1 · System.Random.Internal
RandomGenSMGenDefined in random-1.3.1 · System.Random.Internal
This is a binary form of pseudo-random number generator's state. It is designed to be
safe and easy to use for input/output operations like restoring from file, transmitting
over the network, etc.
Constructor is not exported, becasue it is important for implementation to enforce the
invariant of the underlying byte array being of the exact same length as the generator has
specified in SeedSize. Use mkSeed and
unSeed to get access to the raw bytes in a safe manner.
Instances4Eq, Ord, Show, Uniform
Eq (Seedg)Defined in random-1.3.1 · System.Random.Internal
Ord (Seedg)Defined in random-1.3.1 · System.Random.Internal
Show (Seedg)Defined in random-1.3.1 · System.Random.Internal
SeedGeng => Uniform (Seedg)Defined in random-1.3.1 · System.Random.Seed · orphan
Pseudo-random generators that can be split into two separate and independent
psuedo-random generators should provide an instance for this type class.
Historically this functionality was included in the RandomGen type class in the
split function, however, few pseudo-random generators possess this property of
splittability. This lead the old split function being usually implemented in terms of
error.
Interface for converting a pure pseudo-random number generator to and from non-empty
sequence of bytes. Seeds are stored in Little-Endian order regardless of the platform
it is being used on, which provides cross-platform compatibility, while providing
optimal performance for the most common platform type.
Conversion to and from a Seed serves as a building block for implementing
serialization for any pure or frozen pseudo-random number generator.
It is not trivial to implement platform independence. For this reason this type class
has two alternative ways of creating an instance for this class. The easiest way for
constructing a platform indepent seed is by converting the inner state of a generator
to and from a list of 64 bit words using toSeed64 and fromSeed64 respectively. In
that case cross-platform support will be handled automaticaly.
However, when performance is of utmost importance or default handling of cross platform
independence is not sufficient, then an adventurous developer can try implementing
conversion into bytes directly with toSeed and fromSeed.
Properties that must hold:
> fromSeed (toSeed gen) == gen
> fromSeed64 (toSeed64 gen) == gen
Note, that there is no requirement for every Seed to roundtrip, eg. this proprty does
not even hold for StdGen:
Number of bytes that is required for storing the full state of a pseudo-random
number generator. It should be big enough to satisfy the roundtrip property:
Construct pseudo-random number generator from a list of words. Whenever list does
not have enough bytes to satisfy the SeedSize requirement, it will be padded with
zeros. On the other hand when it has more than necessary, extra bytes will be dropped.
For example if SeedSize is set to 2, then only the lower 16 bits of the first
element in the list will be used.
Number of bytes that is required for storing the full state of a pseudo-random
number generator. It should be big enough to satisfy the roundtrip property:
As an example, rollsM generates n pseudo-random values of Word in the range [1,
6] in a StatefulGen context; given a monadic pseudo-random number generator, you
can run this probabilistic computation using
mwc-random as follows:
Example2 expressions
>>> import Control.Monad (replicateM)>>> :{let rollsM :: StatefulGen g m => Int -> g -> m [Word] rollsM n = replicateM n . uniformRM (1, 6):}
Given a pure pseudo-random number generator, you can run the monadic pseudo-random
number computation rollsM in StateT, IO, ST or STM
context by applying a monadic adapter like StateGenM, AtomicGenM, IOGenM,
STGenM or TGenM (see monadic-adapters) to the pure
pseudo-random number generator.
Functionality for thawing frozen generators is not part of the FrozenGen class,
becase not all mutable generators support functionality of creating new mutable
generators, which is what thawing is in its essence. For this reason StateGen does
not have an instance for this type class, but it has one for FrozenGen.
Here is an important law that relates this type class to FrozenGen
Roundtrip and independence of mutable generators:
traverse thawGen fgs >>= traverse freezeGen = pure fgs
For the sake of example we will use a temporary directory for storing the seed. Here we
report the contents of the seed file before and after we shuffle a list:
Just like withSeedMutableGen, except it doesn't return the final generator, only
the resulting value. This is slightly more efficient, since it doesn't incur overhead
from freezeing the mutable generator
Splits a pseudo-random number generator into two. Overwrites the mutable
pseudo-random number generator with one of the immutable pseudo-random number
generators produced by a split function and returns the other.
Splits a pseudo-random number generator into two. Overwrites the mutable wrapper with
one of the resulting generators and returns the other as a new mutable generator.
StateGenM can be used in any state monad. With strict
StateT there is no performance overhead compared to
using the RandomGen instance directly. StateGenM is not safe to use in the
presence of exceptions and concurrency.
AtomicGenM is safe in the presence of exceptions and concurrency since
it performs all actions atomically.
IOGenM is a wrapper around an IORef that holds a pure generator.
IOGenM is safe in the presence of exceptions, but not concurrency.
STGenM is a wrapper around an STRef that holds a pure generator.
STGenM is safe in the presence of exceptions, but not concurrency.
TGenM is a wrapper around a TVar that holds a pure generator. TGenM
can be used in a software transactional memory monad STM. It is not as
performant as AtomicGenM, but it can provide stronger guarantees in a
concurrent setting.
Runs a monadic generating action in the ST monad using a pure
pseudo-random number generator. Same as runStateGenST, but discards the
resulting generator.
An example use case is writing pseudo-random bytes into a file:
Example3 expressions
>>> import UnliftIO.Temporary (withSystemTempFile)>>> import Data.ByteString (hPutStr)>>> let ioGen g = withSystemTempFile "foo.bin" $ \_ h -> uniformRM (0, 100) g >>= flip uniformByteStringM g >>= hPutStr h
A hypothetical type Radian representing angles by taking values in the
range [0, 2π) has a trivial Uniform instance, but no UniformRange
instance: the problem is that two given Radian values always span two
ranges, one clockwise and one anti-clockwise.
It is trivial to construct a Uniform (a, b) instance given
Uniform a and Uniform b (and this library provides this tuple
instance).
On the other hand, there is no correct way to construct a
UniformRange (a, b) instance based on just UniformRange a and
UniformRange b.
A definition of Uniform for Finite types.
If your data has several fields of sub-Word cardinality,
this instance may be more efficient than one, derived via Generic and GUniform.
isInRange (lo, hi) x ==>
isInRange (lo, x) hi == x == hi
Ranges are transitive relations:
isInRange (lo, hi) lo' && isInRange (lo, hi) hi' && isInRange (lo', hi') x
==> isInRange (lo, hi) x
There is a default implementation of isInRange via Generic. Other helper function
that can be used for implementing this function are isInRangeOrd and
isInRangeEnum.
Note that the isRange method from Data.Ix is not a suitable default
implementation of isInRange. Unlike isInRange, isRange is not
required to be symmetric, and many isRange implementations are not
symmetric in practice.
Generates uniformly distributed Double in the range [0, 1].
Numbers are generated by generating uniform Word64 and dividing
it by 2^{64}. It's used to implement UniformRange instance for
Double.
Generates uniformly distributed Double in the range
(0, 1]. Number is generated as 2^{-64}/2+\operatorname{uniformDouble01M}.
Constant is 1/2 of smallest nonzero value which could be generated
by uniformDouble01M.
Generates uniformly distributed Float in the range [0, 1].
Numbers are generated by generating uniform Word32 and dividing
it by 2^{32}. It's used to implement UniformRange instance for Float.
Generates uniformly distributed Float in the range
(0, 1]. Number is generated as 2^{-32}/2+\operatorname{uniformFloat01M}.
Constant is 1/2 of smallest nonzero value which could be generated
by uniformFloat01M.
Generates uniformly distributed Enum in the given range.
One can use it to define a UniformRange instance:
data Colors = Red | Green | Blue deriving (Enum)
instance UniformRange Colors where
uniformRM = uniformEnumRM
inInRange (lo, hi) x = isInRange (fromEnum lo, fromEnum hi) (fromEnum x)
Typically, a monadic pseudo-random number generator has facilities to save
and restore its internal state in addition to generating pseudo-random numbers.
Here is an example instance for the monadic pseudo-random number generator
from the mwc-random package:
import qualified System.Random.MWC as MWC
import qualified Data.Vector.Generic as G
instance (s ~ PrimState m, PrimMonad m) => StatefulGen (MWC.Gen s) m where
uniformWord8 = MWC.uniform
uniformWord16 = MWC.uniform
uniformWord32 = MWC.uniform
uniformWord64 = MWC.uniform
uniformByteArrayM isPinned n g = stToPrim (fillByteArrayST isPinned n (MWC.uniform g))
instance PrimMonad m => FrozenGen MWC.Seed m where
type MutableGen MWC.Seed m = MWC.Gen (PrimState m)
freezeGen = MWC.save
overwriteGen (Gen mv) (Seed v) = G.copy mv v
instance PrimMonad m => ThawedGen MWC.Seed m where
thawGen = MWC.restore
FrozenGen
FrozenGen gives us ability to use most of stateful pseudo-random number generator in
its immutable form, if one exists that is. The biggest benefit that can be drawn from
a polymorphic access to a stateful pseudo-random number generator in a frozen form is
the ability to serialize, deserialize and possibly even use the stateful generator in a
pure setting without knowing the actual type of a generator ahead of time. For example
we can write a function that accepts a frozen state of some pseudo-random number
generator and produces a short list with random even integers.
Example3 expressions
>>> import Data.Int (Int8)>>> import Control.Monad (replicateM)>>> :{myCustomRandomList :: ThawedGen f m => f -> m [Int8]myCustomRandomList f = withMutableGen_ f $ \gen -> do len <- uniformRM (5, 10) gen replicateM len $ do x <- uniformM gen pure $ if even x then x else x + 1:}
and later we can apply it to a frozen version of a stateful generator, such as STGen:
Alternatively, instead of discarding the final state of the generator, as it happens
above, we could have used withMutableGen, which together with the result would give
us back its frozen form. This would allow us to store the end state of our generator
somewhere for the later reuse.
This is the function that is used to scale a floating point value from random word range to
the custom [low, high] range.
Due to rounding errors, floating point operations are neither associative nor
distributive the way the corresponding operations on real numbers are. Additionally,
floating point numbers admit special values NaN as well as negative and positive
infinity.
The UniformRange instances for Float and Double use the following
procedure to generate a random value in a range for uniformRM (l, h) g:
Generate an unsigned integral of matching width w uniformly.
Check whether h - l overflows to infinity and, if it does, then convert
w to a floating point number in [0.0, 1.0] range through division
of w by the highest possible value:
max (min (x * l + (1 - x) * h) (max l h)) (min l h)
Clamping is necessary, because otherwise it would be possible to run into a
degenerate case when a scaled value is outside the specified range due to
rounding errors.
Whenever h - l does not overflow, we use this common formula for scaling:
l + (h - l) * x. However, instead of using [0.0, 1.0] range we
use the top most bit of w to decide whether we will treat the generated
floating point value as [0.0, 0.5] range or [0.5, 1.0] range and
use the left over bits to produce a floating point value in the half unit
range:
if testBit w 31
then l + (h - l) * x
else h + (l - h) * x
Because of this clever technique the result does not need clamping, since
scaled values are guaranteed to stay within the specified range. Another reason
why this tecnique is used for the common case instead of the one described in
2. is because it avoids usage of 1 - x, which consequently reduces loss
of randomness due to rounding.
What happens when NaN or Infinity are given to uniformRM? We first
define them as constants:
Example3 expressions
>>> nan = read "NaN" :: Float>>> inf = read "Infinity" :: Float>>> g <- newIOGenM (mkStdGen 2024)
If at least one of l or h is NaN, the result is NaN.
Guy L. Steele, Jr., Doug Lea, and Christine H. Flood. 2014. Fast
splittable pseudorandom number generators. In Proceedings of the 2014 ACM
International Conference on Object Oriented Programming Systems Languages &
Applications (OOPSLA '14). ACM, New York, NY, USA, 453-472. DOI:
https://doi.org/10.1145/2660193.2660195