'a Quickcheck.Observer.t represents observations that can be made to
distinguish values of type
'a. An observer maps values of type
'a to disjoint
subsets ("buckets") using a finite number of observations.
Observers are used to construct distributions of random functions; see
One constructs an observer by breaking down an input into basic type constituents
that can be individually observed. Use built-in observers for basic types when
either or the
variant* observers to distinguish clauses of
variants. Use the
tuple* observers to get at individual fields of tuples or
records. When you have a custom type with no built-in observer, construct an
observer for an equivalent type, then use
recursive to build
observers for recursive types. See the below example for a binary search tree:
type 'a bst = Leaf | Node of 'a bst * 'a * 'a bst let bst_obs key_obs = recursive (fun bst_of_key_obs -> unmap (Either.obs Unit.obs (tuple3 bst_of_key_obs key_obs bst_of_key_obs)) ~f:(function | Leaf -> First () | Node (l, k, r) -> Second (l, k, r)) ~f_sexp:(fun () -> Sexp.Atom "either_of_bst"))
Fixed point observer; use
recursive to create observers for recursive types. For
let sexp_obs = recursive (fun sexp_t -> unmap (variant2 string (list sexp_t)) ~f:(function | Sexp.Atom atom -> `A atom | Sexp.List list -> `B list) ~f_sexp:(fun () -> Sexp.Atom "variant_of_sexp"))
comparison ~compare ~eq ~lt ~gt combines observers
observes values less than
eq according to
gt observes values
eq according to
branching_factor t produces the number of nodes in the decision tree of
one less than the number of buckets in
t. This value is artificially capped at
2^15-1 in order to avoid intractable function generators and overflow in arithmetic.
The result may be an overapproximation for observers constructed with
observe t gen ~sexp_of_rng ~branching_factor constructs a generator for a function
t to observe the domain and
gen to generate the range. Each
generated function also comes with a (lazy, unmemoized) sexp describing it. The
size of the function's decision tree is determined by
branching_factor and the
sexps of its return values are constructed by
The functions in the resulting generator will all be intensionally unique: no two will make the same set of decisions in the same order. However, as two such functions may make the same set of decisions in a different order, they will not be extensionally unique. While it would be nice to have distributions of extensionally unique functions, implementing such a generator is quite difficult, and likely not worth the effort.
maps all values to a single bucket.
Nondeterministic observer. Presents a weighted choice of multiple observers. When
observe builds a decision tree, it randomly chooses nodes from any of these
observers with probability proportional to the given weights. All weights must be
finite and non-negative.
Observer for function type.
fn ~p gen t ~sexp_of_dom observes a function by
generating random inputs from
gen, applying the function, and observing the output
observe builds a single random decision tree node from the result of
chooses between generating a new input and observing a previously generated input.
It does the former with probability
p and the latter with probability
1. -. p.
p defaults to 0.25, and must be between 0 and 1 (both inclusive).
of_fun f produces an observer that lazily applies
It is recommended that
f should not do a lot of expensive work and should not be
memoized. Instead, spread out the work of generating an observer over many
calls combined with, e.g.,
tuple. This allows lazily generated
observers to be garbage collected after each test and the relevant portions cheaply
recomputed in subsequent tests, rather than accumulating without bound over time.