Module Base_quickcheck.Generator

Generators are sources of random values. Every randomized test needs a generator to produce its inputs.

type +'a t

Basic Generators

val unit : 'a t
val bool : 'a t
val char : 'a t
val string : 'a t
val int : 'a t
val int32 : 'a t
val int63 : 'a t
val int64 : 'a t
val nativeint : 'a t
val float : 'a t
val sexp : 'a t
val option : 'a t -> 'a t
val list : 'a t -> 'a t
val both : 'a t -> 'a t -> 'a t
val either : 'a t -> 'a t -> 'a t
val result : 'a t -> 'a t -> 'a t
val bigstring : 'a t
val float32_vec : 'a t
val float64_vec : 'a t
val float32_mat : 'a t
val float64_mat : 'a t
val fn : 'a Base_quickcheck__Observer0.t -> 'b t -> ('a -> 'b) t

Generates random functions that use the given observer to perturb the pseudo-random state that is then used to generate the output value. The resulting functions are therefore deterministic, assuming the observer is deterministic.

val map_t_m : ('key'cmp) Base.Set.comparator -> 'key t -> 'data t -> ('key'data'cmp) Base.Map.t t
val set_t_m : ('elt'cmp) Base.Set.comparator -> 'elt t -> ('elt'cmp) Base.Set.t t
val map_tree_using_comparator : comparator:('key'cmp) Base.Comparator.t -> 'key t -> 'data t -> ('key'data'cmp) Base.Map.Using_comparator.Tree.t t
val set_tree_using_comparator : comparator:('elt'cmp) Base.Comparator.t -> 'elt t -> ('elt'cmp) Base.Set.Using_comparator.Tree.t t

Combining and Modifying Generators

val of_list : 'a Base.list -> 'a t

Produces any of the given values, weighted uniformly.

val union : 'a t Base.list -> 'a t

Chooses among the given generators, weighted uniformly; then chooses a value from that generator.

include Base.Applicative.S with type 'a t := 'a t
val return : 'a -> 'a t
val map : 'a t -> f:('a -> 'b) -> 'a t
val both : 'a t -> 'a t -> 'a t
val (<*>) : 'a t -> 'a t -> 'a t

same as apply

val (<*) : 'a t -> 'a t -> 'a t
val (*>) : 'a t -> 'a t -> 'a t
val (>>|) : 'a t -> ('a -> 'b) -> 'a t
val apply : 'a t -> 'a t -> 'a t
val map2 : 'a t -> 'a t -> f:('a -> 'b -> 'c) -> 'a t
val map3 : 'a t -> 'a t -> 'a t -> f:('a -> 'b -> 'c -> 'd) -> 'a t
val all : 'a t list -> 'a t
val all_unit : 'a t list -> 'a t
module Applicative_infix : sig ... end
include Base.Monad.S with type 'a t := 'a t
val (>>=) : 'a t -> ('a -> 'a t) -> 'a t

t >>= f returns a computation that sequences the computations represented by two monad elements. The resulting computation first does t to yield a value v, and then runs the computation returned by f v.

val (>>|) : 'a t -> ('a -> 'b) -> 'a t

t >>| f is t >>= (fun a -> return (f a)).

module Monad_infix : sig ... end
val bind : 'a t -> f:('a -> 'a t) -> 'a t

bind t ~f = t >>= f

val return : 'a -> 'a t

return v returns the (trivial) computation that returns v.

val map : 'a t -> f:('a -> 'b) -> 'a t

map t ~f is t >>| f.

val join : 'a t -> 'a t

join t is t >>= (fun t' -> t').

val ignore_m : 'a t -> 'a t

ignore_m t is map t ~f:(fun _ -> ()). ignore_m used to be called ignore, but we decided that was a bad name, because it shadowed the widely used Caml.ignore. Some monads still do let ignore = ignore_m for historical reasons.

val all : 'a t list -> 'a t
val all_unit : 'a t list -> 'a t

Like all, but ensures that every monadic value in the list produces a unit value, all of which are discarded rather than being collected into a list.

module Let_syntax : sig ... end

Size of Random Values

val size : Base.int t

Returns the current size parameter.

val with_size : 'a t -> size:Base.int -> 'a t

Produces a generator that ignores the size parameter passed in by Base_quickcheck and instead uses the given ~size argument. Most often used with size to reduce the size when dispatching to generators for subparts of a value.

For example, here is a use of with_size and size to create a generator for optional lists. We are careful to generate None even at non-zero sizes; see the note above about not using size as a lower bound.

let optional_list generator =
  let open Let_syntax in
  match%bind both size bool with
  | (0, _) | (_, false) -> return None
  | k, _ ->
    let%map elements = with_size ~size:(k-1) (list generator) in
    Some elements
val sizes : ?⁠min_length:Base.int -> ?⁠max_length:Base.int -> Base.unit -> Base.int Base.list t

Produces a list of sizes that distribute the current size among list elements. The min_length and max_length parameters can be used to bound the length of the result.

This is the distribution used by generators such as list to divide up size among elements.

This function is designed so that elements of list are always generated at strictly smaller size than the list itself. The technical invariant is: if size_list is generated by with_size ~size:n (sizes ~min_length ()), then:

(List.length size_list - min_length) + (List.sum (module Int) size_list)
<= n

Filtering Generators

val filter : 'a t -> f:('a -> Base.bool) -> 'a t

Produces values for which f returns true. If f returns false, retries with size incremented by 1. This avoids filter getting stuck if all values at a given size fail f; see the note above about not using size as a lower bound.

val filter_map : 'a t -> f:('a -> 'b Base.option) -> 'b t

When f produces Some x, produces x. If f returns None, retries with size incremented by 1, as with filter.

Generating Recursive Values

val recursive_union : 'a t Base.list -> f:('a t -> 'a t Base.list) -> 'a t

Ties the recursive knot to produce generators for recursive types that have multiple clauses, separating base cases from recursive cases. At size 0, only base cases are produced; at size n > 0, the base cases are produced at size n along with the recursive cases at size n-1. Raises if the list of base cases is empty or if the list of recursive cases is empty.

For example, here is a use of recursive_union to create a generator for an expression datatype.

type exp =
  | Int  of int
  | Bool of bool
  | If   of exp * exp * exp
  | Add  of exp * exp

let exp_generator =
  recursive_union
    [
      map int ~f:(fun i -> Int i);
      map bool ~f:(fun b -> Bool b);
    ]
    ~f:(fun exp ->
      let open Let_syntax in
      [
        (let%map a = exp and b = exp and c = exp in If (a, b, c));
        (let%map a = exp and b = exp in Add (a, b));
      ])
val fixed_point : ('a t -> 'a t) -> 'a t

Like recursive_union, without separate clauses or automatic size management. Useful for generating recursive types that don't fit the clause structure of recursive_union.

For example, here is a use of fixed_point to create a generator for N-ary trees. No manual size management is needed, as Generator.list guarantees to generate list elements at strictly smaller sizes than the list itself.

type tree = Node of tree list
let tree_generator =
  fixed_point (fun tree ->
    map (list tree) ~f:(fun trees -> Node trees))
val of_lazy : 'a t Base.Lazy.t -> 'a t

Creates a t that forces the lazy argument as necessary. Can be used to tie (mutually) recursive knots.

Custom Random Distributions

val of_weighted_list : (Base.float * 'a) Base.list -> 'a t

Produces one of the given values, chosen with the corresponding weight. Weights must be non-negative and must have a strictly positive sum.

val weighted_union : (Base.float * 'a t) Base.list -> 'a t

Produces one of the given generators, chosen with the corresponding weight, then chooses a value from that generator. Weights must be non-negative and must have a strictly positive sum.

val weighted_recursive_union : (Base.float * 'a t) Base.list -> f:('a t -> (Base.float * 'a t) Base.list) -> 'a t

Like recursive_union, with explicit weights for each clause. Weights must be non-negative and the recursive case weights must have a strictly positive sum.

Integer Distributions

val small_positive_or_zero_int : Base.int t

Produces an integer between 0 and an unspecified upper bound which is proportional to size. This is a good generator to use for sizes of values like strings which have a variable number of fixed-size elements.

val small_strictly_positive_int : Base.int t

Like small_positive_or_zero_int but with a minimum of 1.

Uniform Unbounded Distributions
val int_uniform : Base.int t
val int32_uniform : Base.int32 t
val int63_uniform : Base.Int63.t t
val int64_uniform : Base.int64 t
val nativeint_uniform : Base.nativeint t
Bounded Distributions
val int_inclusive : Base.int -> Base.int -> Base.int t
val int32_inclusive : Base.int32 -> Base.int32 -> Base.int32 t
val int63_inclusive : Base.Int63.t -> Base.Int63.t -> Base.Int63.t t
val int64_inclusive : Base.int64 -> Base.int64 -> Base.int64 t
val nativeint_inclusive : Base.nativeint -> Base.nativeint -> Base.nativeint t
Uniform Bounded Distributions
val int_uniform_inclusive : Base.int -> Base.int -> Base.int t
val int32_uniform_inclusive : Base.int32 -> Base.int32 -> Base.int32 t
val int63_uniform_inclusive : Base.Int63.t -> Base.Int63.t -> Base.Int63.t t
val int64_uniform_inclusive : Base.int64 -> Base.int64 -> Base.int64 t
val nativeint_uniform_inclusive : Base.nativeint -> Base.nativeint -> Base.nativeint t
Uniform in Log Space Distributions
val int_log_uniform_inclusive : Base.int -> Base.int -> Base.int t
val int32_log_uniform_inclusive : Base.int32 -> Base.int32 -> Base.int32 t
val int63_log_uniform_inclusive : Base.Int63.t -> Base.Int63.t -> Base.Int63.t t
val int64_log_uniform_inclusive : Base.int64 -> Base.int64 -> Base.int64 t
val nativeint_log_uniform_inclusive : Base.nativeint -> Base.nativeint -> Base.nativeint t
Log Space Distributions
val int_log_inclusive : Base.int -> Base.int -> Base.int t
val int32_log_inclusive : Base.int32 -> Base.int32 -> Base.int32 t
val int63_log_inclusive : Base.Int63.t -> Base.Int63.t -> Base.Int63.t t
val int64_log_inclusive : Base.int64 -> Base.int64 -> Base.int64 t
val nativeint_log_inclusive : Base.nativeint -> Base.nativeint -> Base.nativeint t

Floating Point Distributions

val float_inclusive : Base.float -> Base.float -> Base.float t

Generates values between the given bounds, inclusive, which must be finite and in nondecreasing order. Weighted toward boundary values.

val float_uniform_exclusive : Base.float -> Base.float -> Base.float t

Generates values between the given bounds, exclusive, which must be finite and in increasing order, with at least one float value between them. Weighted approximately uniformly across the resulting range, rounding error notwithstanding.

val float_without_nan : Base.float t
val float_finite : Base.float t
val float_strictly_positive : Base.float t
val float_strictly_negative : Base.float t
val float_positive_or_zero : Base.float t
val float_negative_or_zero : Base.float t
val float_of_class : Base.Float.Class.t -> Base.float t

Character Distributions

val char_lowercase : Base.char t
val char_uppercase : Base.char t
val char_digit : Base.char t
val char_alpha : Base.char t
val char_alphanum : Base.char t
val char_whitespace : Base.char t
val char_print : Base.char t
val char_uniform_inclusive : Base.char -> Base.char -> Base.char t

String Distributions

val string_non_empty : Base.string t
val string_with_length : length:Base.int -> Base.string t
val string_of : Base.char t -> Base.string t
val string_non_empty_of : Base.char t -> Base.string t
val string_with_length_of : Base.char t -> length:Base.int -> Base.string t

Sexp Distributions

val sexp_of : Base.string t -> Base.Sexp.t t

Produces s-expressions whose atoms are chosen from the given string distribution.

List Distributions

val list_non_empty : 'a t -> 'a Base.list t
val list_with_length : 'a t -> length:Base.int -> 'a Base.list t
val list_filtered : 'a Base.list -> 'a Base.list t

Randomly drops elements from a list. The length of each result is chosen uniformly between 0 and the length of the input, inclusive.

val list_permutations : 'a Base.list -> 'a Base.list t

Produces permutations of the given list, weighted uniformly.

Low-Level Interface

val perturb : 'a t -> Base.int -> 'a t

Passes in additional "salt" used to perturb the pseudo-random state used to generate random values. Generators' output is intended to be deterministic for any initial pseudorandom state, so perturb can be used to generate a new generator with the same distribution that nonetheless produces different values from the original for any given pseudo-random state.

val create : (size:Base.int -> random:Splittable_random.State.t -> 'a) -> 'a t

Creates a generator that calls the given function with the current size parameter and pseudorandom state.

val generate : 'a t -> size:Base.int -> random:Splittable_random.State.t -> 'a

Generates a random value using the given size and pseudorandom state. Useful when using create and dispatching to other existing generators.