This library provides the ability for a user to generate random values of arbitrary type. It provides a pure-functional interface to preserve equational reasoning. Existing combinator libraries are provided for built-in data types. For example:
- Generating random product types (tuples) given generators for its components.
- Generating random sum types given generators for its constructors
scala.Eitherscalaz.\/scalaz.Validation
Example usages are provided in the /examples source directory.
To use the library, add the following to your SBT configuration:
libraryDependencies += "com.nicta" %% "rng" % "1.3.0"(changing the version number if necessary).
A generator is represented by the Rng data type. A value of the type Rng[T] will produce random values of the type
T. For example, to generate random pairs (X, Y) and given a Rng[X] (call it randomX) and a Rng[Y]
(call it randomY), use the zip function:
val randomPair: Rng[(X, Y)] =
randomX zip randomYTo generate random sum type (X \/ Y) and given a Rng[X] (call it randomX) and a Rng[Y] (call it randomY), use
the either function:
val randomEither: Rng[(X \/ Y)] =
randomX either randomYThe Rng data type uses a specific technique for ensuring a pure-functional programming interface. It utilises
the free monad by defining a grammar for manipulation by the free monad.
The grammar is defined by the RngOp data type, which defines two primitive operations:
nextbitswhich is expected to produce a random integersetseedwhich manipulates the seed for random generation
All other random generation operations are defined in terms of these two primitive operations.
The library user manipulates random generation by essentially building up a program that is composed of combinations of these operations. Although it is important to understand this programming model, the library user is effectively insulated by higher-level libraries. Users can expect the types provided by the library to dictate purpose. This robustness is a consequence of the pure-functional programming interface. Side-effects are guaranteed to never occur.
The run method on Rng executes the grammar and returns an IO action to manipulate the value arbitrary. The
provided examples demonstrate how to achieve this.
Th RngOp data type underlies the random generator by providing a grammar with two instructions (nextbits and
setseed). Programming the RngOp data type directly is atypical and users might consider the higher-level library
provided on the Rng data type instead. The RngOp type constructor forms a comonad and so has operations for
manipulating the operation:
- The
mapmethod onRngOp[A]accepts a function (A => B) and returns aRngOp[B] - The
coflatMapmethod onRngOp[A]accepts a function (RngOp[A] => B) and returns aRngOp[B]
RngOp values can then be lifted to a generator (Rng) using the lift method.
Many random generators are provided, such as:
- The
optionmethod produces a generator forRng[Option[T]]when the method is called on a value of the typeRng[T]. - The
listmethod produces a generator forRng[List[T]]when the method is called on a value of the typeRng[T]. - The
list1method produces a generator forRng[NonEmptyList[T]]when the method is called on a value of the typeRng[T]. - Generators for primitive types provided as functions on the
Rngobject:intto generate random integer valuesbyteto generate random byte valuesshortto generate random short valueslongto generate random long valuesdoubleto generate random double valuesfloatto generate random float valuesbooleanto generate random boolean valuesshortto generate random short valuescharto generate random character valuescharsto generate random lists of character valueschars1to generate random non-empty lists of character values- Upper-case characters
upperto generate random upper-case (A-Z) character valuesuppersto generate random lists of upper-case (A-Z) character valuesuppers1to generate random non-empty lists of upper-case (A-Z) character valuesupperstringto generate random strings of upper-case (A-Z) character valuesupperstring1to generate random non-empty strings of upper-case (A-Z) character values
- Lower-case characters
lowerto generate random lower-case (a-z) character valueslowersto generate random lists of lower-case (a-z) character valueslowers1to generate random non-empty lists of lower-case (a-z) character valueslowerstringto generate random strings of lower-case (a-z) character valueslowerstring1to generate random non-empty strings of lower-case (a-z) character values
- Alpha characters
alphato generate random alpha (a-z and A-Z) character valuesalphasto generate random lists of alpha (a-z and A-Z)character valuesalphas1to generate random non-empty lists of (a-z and A-Z) alpha character valuesalphastringto generate random strings of alpha (a-z and A-Z) character valuesalphastring1to generate random non-empty strings of alpha (a-z and A-Z) character values
- Numeric characters
numericto generate random numeric (0-9) character valuesnumericsto generate random lists of numeric (0-9) character valuesnumerics1to generate random non-empty lists of numeric (0-9) character valuesnumericstringto generate random strings of numeric (0-9) character valuesnumericstring1to generate random non-empty strings of numeric (0-9) character values
- Alpha-numeric characters
alphanumericto generate random alpha-numeric (a-z, A-Z and 0-9) character valuesalphanumericsto generate random lists of alpha-numeric (a-z, A-Z and 0-9) character valuesalphanumerics1to generate random non-empty lists of alpha-numeric (a-z, A-Z and 0-9) character valuesalphanumericstringto generate random strings of alpha-numeric (a-z, A-Z and 0-9) character valuesalphanumericstring1to generate random non-empty strings of alpha-numeric (a-z, A-Z and 0-9) character values
- Identifiers (an identifier is defined by a string of characters starting with an alpha character, followed by zero
or more alpha-numeric characters)
identifierfor generating random non-empty lists of characters representing an identifieridentifierstringfor generating random non-empty strings representing an identifier
- Proper noun (a proper noun is defined by a string of characters starting with an upper-case character, followed by
zero or more lower-case characters)
propernounfor generating random non-empty lists of characters representing a proper nounpropernounstringfor generating random non-empty strings representing a proper noun
- Integer ranges
negative(double/float/long/int)to generate random negative doubles/floats/longs/integerspositive(double/float/long/int)to generate random positive doubles/floats/longs/integerschooseintto generate random integers in a given rangechooselongto generate random longs in a given rangechoosefloatto generate random floats in a given rangechoosedoubleto generate random doubles in a given range
- Generators for values of the
scalaz.Digitdata type provided as functions on theRngobject:digitto generate random digit valuesdigitsto generate random lists of digit valuesdigits1to generate random non-empty lists of digit values
- Generators for manipulating lists of values
oneofaccepts a non-empty (variable argument) list of values and returns a generator that produces one of those valuesoneofLdoes the same asoneof, however, it is accepts an argument ofscalaz.NonEmptyListinstead of a non-empty argument list.frequencyaccepts a non-empty (variable argument) list of pairs of values. The pair is an integer and a random generator where the integer represents the skewed frequency of the associated random generator. ThefrequencyLfunction returns a generator that will select from the given list of generators with a skewed distribution.frequencyLdoes the same asfrequency, however, it is accepts an argument ofscalaz.NonEmptyListinstead of a non-empty argument list.
- Distributing and traversing generators
sequencefor taking a traversable of generators to a generator of traversables. A Traversable value is represented as a generalised interface (scalaz.Traverse).distributefor taking a generator of distributive values to a distribution of generators. A distributive value is represented as a generalised interface (scalaz.Distributive).
The Rng type constructor forms a monad making it trivial to combine existing random generators for user-defined data
types. For example, consider a data type combined of products and sums:
case class Person(name: String, age: Option[Int])A random generator can be constructed by combining random generators for String, Int and Option using a
for-comprehension:
val randomPerson: Rng[Person] =
for {
n <- Rng.string
a <- Rng.int.option
} yield Person(n, a)Documentation for this library is provided by this document, example usages and static-type verification. The statically verified constraints provided by this library are a consequence of the pure-functional programming interface.