Commit 4eb389a5 authored by Andy Li's avatar Andy Li

Imported Upstream version 0.8

parents
.*.swp
.*.swo
_build
*.native
.session
TAGS
*.docdir
man
qcheck.install
*.tar.gz
*.byte
.merlin
[submodule "check-fun"]
path = check-fun
url = https://github.com/jmid/qcheck-fun
(*
QCheck: Random testing for OCaml
copyright (c) 2013-2017, Guillaume Bury, Simon Cruanes, Vincent Hugot, Jan Midtgaard
all rights reserved.
*)
#directory "_build/src";;
#use "topfind";;
#require "oUnit";;
#require "unix";;
#require "bytes";;
#load "qcheck.cma";;
open QCheck;;
(* vim: syntax=ocaml:
*)
Simon Cruanes <simon.cruanes.2007@m4x.org>
Rudi Grinberg <rudi.grinberg@gmail.com>
Jacques-Pascal Deplaix <jp.deplaix@gmail.com>
Jan Midtgaard <mail@janmidtgaard.dk>
# Changes
## 0.7
- switch to BSD license, make it more explicit (close #43)
- improve multi-line message printing in ounit (closes #46)
- fix complexity of `add_stat`
- allow negative entries in statistics (see #40)
- add a way for tests to report messages to the user (see #39)
- add `QCheck.Shrink.int_aggressive` and make default int shrinker faster
- shrinker for `map_keep_input`
- add `QCheck.set_gen`, missing for some reason
- more compact verbose output (see #33)
- better handling of dynamic progress line
- Add colors to checkmarks in verbose mode
- improve statistics display for runner
- recover exception of shrunk input
- print status line before the solving starts
## 0.6
- add `find_example` and `find_example_gen` to synthesize values from
properties (see #31)
- add `QCheck.gen` for accessing the random generator easily
- colorful runners, with `--no-colors` to disable them
- add more generator (for corner cases)
- better generation of random functions (see #8),
using `Observable` and an efficient internal representation using
heterogeneous tuples, printing, and shrinking. deprecate old hacks.
- add statistics gathering and display (see #30)
- better printing of Tuple
- improve `Shrink.{array,list}` (see #32)
- Change asserts to raise `Invalid_arg` (following the doc), and update doc
- Change `Gen.{int_bount,int_range}` to support up to 2^62
## 0.5.3.1
- fix regression in runner output (print results of `collect`)
- update the `@since` tags
## 0.5.3
- missing char in `Gen.char` (close #23)
- add `test` and `doc` to opam
- add `small_list` generator
- add `~long_factor` to tests and runner, for long tests
- add more examples in readme, better doc for runners
- improved reporting when running qcheck tests
- add `Test.get_count` on test cells
## 0.5.2
- Add cli option for backtraces in `QCheck_runner`
- Add test case for raising exception
- Better handling of backtraces
- All tests now have a name
- Add step function called on each instance in a test
- make `small_int` a deprecated alias to `small_nat`
- add `small_signed_int`
- remove some warnings
- use safe-string, and fix related bug
- Add long tests options to `QCheck_runner`
- Add `length` specification for `to_ounit2_test`
- Added paragraph in README about long tests
## 0.5.1
- document exceptions
- add `small_nat`, change `small_int` semantics (close #10)
- add `QCheck.assume_fail`
- add `QCheck.assume`; explain preconditions a bit (close #9)
- Polish documentation
- Added quad support uniformly
## 0.5
- merge back from `qtest`: big changes in API, shrinking, use `'a arbitrary`
type that combines printer, generator, shrinker, etc. (see git log)
- merlin file
- reorganize sources, `_oasis`, `.merlin`, etc.
## 0.4
- bugfix in `fix_fuel`
- if verbose enabled, print each test case
- add `QCheck.run_main`
- `QCheck_ounit.~::`
- add `(>:::)`
- add `qcheck_ounit ml{lib,dylib}`
- trivial ounit integration
- make `test_cell.name` optional
- `Arbitrary.fix_fuel(_gen)`: add a recursive case
- `Arbitrary.fix_fuel_gen`, similar to `fix_fuel` but threading a state bottom-up to make choices depend on the path
- `Arbitrary.fail_fix` to fail in a fixpoint
- helper cases for `Arbitrary.fix_fuel`
## 0.3
- get rid of submodule `generator`
- `Arbitrary.fix_fuel`, to generate complex recursive structures
- new combinators (infix map, applicative funs, shuffle)
- remove generator/Generator, and a deprecation warning
- output of printers of lists/arrays now parsable by ocaml toplevel
## 0.2
- integrate Gabriel Scherer's `Generator` into `QCheck`
- add `|||`
- add `Prop.raises`
- print the faulty instance in case of error (if a printer is available)
- some combinators for `QCheck.Arbitrary`
- `QCheck.mk_test` takes more arguments
## 0.1
- oasis based build system
- source files
copyright (c) 2013-2017, Guillaume Bury, Simon Cruanes, Vincent Hugot, Jan Midtgaard
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer. Redistributions in binary
form must reproduce the above copyright notice, this list of conditions and
the following disclaimer in the documentation and/or other materials
provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
all: build test
build:
jbuilder build @install
test:
jbuilder runtest --no-buffer
clean:
jbuilder clean
doc:
jbuilder build @doc
EXAMPLES=$(addprefix example/, QCheck_test.exe QCheck_ounit_test.exe QCheck_runner_test.exe)
examples:
jbuilder build $(EXAMPLES)
VERSION=$(shell awk '/^version:/ {print $$2}' qcheck.opam)
update_next_tag:
@echo "update version to $(VERSION)..."
sed -i "s/NEXT_VERSION/$(VERSION)/g" src/*.ml src/*.mli
sed -i "s/NEXT_RELEASE/$(VERSION)/g" src/*.ml src/*.mli
release: update_next_tag
@echo "release version $(VERSION)..."
git tag -f $(VERSION) ; git push origin :$(VERSION) ; git push origin $(VERSION)
opam publish prepare https://github.com/c-cube/qcheck/archive/$(VERSION).tar.gz
@echo "review the release, then type 'opam publish submit qcheck.$(VERSION)/'"
watch:
while find src/ -print0 | xargs -0 inotifywait -e delete_self -e modify ; do \
echo "============ at `date` ==========" ; \
sleep 0.2; \
make all; \
done
.PHONY: benchs tests examples update_next_tag watch release
= QCheck
:toc: macro
:toclevels: 4
:source-highlighter: pygments
QuickCheck inspired property-based testing for OCaml, and combinators to
generate random values to run tests on.
The documentation can be found https://c-cube.github.io/qcheck/[here].
This library spent some time in
https://github.com/vincent-hugot/iTeML[qtest], but is now
standalone again!
Note that @gasche's
http://gasche.github.io/random-generator/doc/Generator.html[generator library]
can be useful too, for generating random values.
toc::[]
== Use
See the documentation. I also wrote
http://cedeela.fr/quickcheck-for-ocaml.html[a blog post] that explains
how to use it and some design choices; however, be warned that the API
changed in lots of small ways (in the right direction, I hope) so the code
will not work any more.
<<examples>> is an updated version of the blog post's examples.
== Build
$ make
You can use opam:
$ opam install qcheck
== License
The code is now released under the BSD license.
[[examples]]
== An Introduction to the Library
First, let's see a few tests. Let's open a toplevel (e.g. utop)
and type the following to load QCheck:
[source,OCaml]
----
#require "qcheck";;
----
=== List Reverse is Involutive
We write a random test for checking that `List.rev (List.rev l) = l` for
any list `l`:
[source,OCaml]
----
let test =
QCheck.Test.make ~count:1000 ~name:"list_rev_is_involutive"
QCheck.(list small_nat)
(fun l -> List.rev (List.rev l) = l);;
(* we can check right now the property... *)
QCheck.Test.check_exn test;;
----
In the above example, we applied the combinator `list` to
the random generator `small_nat` (ints between 0 and 100), to create a
new generator of lists of random integers. These builtin generators
come with printers and shrinkers which are handy for outputting and
minimizing a counterexample when a test fails.
Consider the buggy property `List.rev l = l`:
[source,OCaml]
----
let test =
QCheck.Test.make ~count:1000 ~name:"my_buggy_test"
QCheck.(list small_nat)
(fun l -> List.rev l = l);;
----
When we run this test we are presented with a counterexample:
[source,OCaml]
----
# QCheck.Test.check_exn test;;
Exception:
QCheck.Test.Test_fail ("my_buggy_test", ["[0; 1] (after 23 shrink steps)"]).
----
In this case QCheck found the minimal counterexample `[0;1]` to the property
`List.rev l = l` and it spent 23 steps shrinking it.
Now, let's run the buggy test with a decent runner that will print the results
nicely (the exact output will change at each run, because of the random seed):
----
# QCheck_runner.run_tests [test];;
--- Failure --------------------------------------------------------------------
Test my_buggy_test failed (10 shrink steps):
[0; 1]
================================================================================
failure (1 tests failed, 0 tests errored, ran 1 tests)
- : int = 1
----
For an even nicer output `QCheck_runner.run_tests` also accepts an optional
parameter `~verbose:true`.
=== Mirrors and Trees
`QCheck` provides many useful combinators to write
generators, especially for recursive types, algebraic types,
and tuples.
Let's see how to generate random trees:
[source,OCaml]
----
type tree = Leaf of int | Node of tree * tree
let leaf x = Leaf x
let node x y = Node (x,y)
let tree_gen = QCheck.Gen.(sized @@ fix
(fun self n -> match n with
| 0 -> map leaf nat
| n ->
frequency
[1, map leaf nat;
2, map2 node (self (n/2)) (self (n/2))]
));;
(* generate a few trees, just to check what they look like: *)
QCheck.Gen.generate ~n:20 tree_gen;;
let arbitrary_tree =
let open QCheck.Iter in
let rec print_tree = function
| Leaf i -> "Leaf " ^ (string_of_int i)
| Node (a,b) -> "Node (" ^ (print_tree a) ^ "," ^ (print_tree b) ^ ")"
in
let rec shrink_tree = function
| Leaf i -> QCheck.Shrink.int i >|= leaf
| Node (a,b) ->
of_list [a;b]
<+>
(shrink_tree a >|= fun a' -> node a' b)
<+>
(shrink_tree b >|= fun b' -> node a b')
in
QCheck.make tree_gen ~print:print_tree ~shrink:shrink_tree;;
----
Here we write a generator of random trees, `tree_gen`, using
the `fix` combinator. `fix` is *sized* (it is a function from `int` to
a random generator; in particular for size 0 it returns only leaves).
The `sized` combinator first generates a random size, and then applies
its argument to this size.
Other combinators include monadic abstraction, lifting functions,
generation of lists, arrays, and a choice function.
Then, we define `arbitrary_tree`, a `tree QCheck.arbitrary` value, which
contains everything needed for testing on trees:
- a random generator (mandatory), weighted with `frequency` to
increase the chance of generating deep trees
- a printer (optional), very useful for printing counterexamples
- a *shrinker* (optional), very useful for trying to reduce big
counterexamples to small counterexamples that are usually
more easy to understand.
The above shrinker strategy is to
- reduce the integer leaves, and
- substitute an internal `Node` with either of its subtrees or
by splicing in a recursively shrunk subtree.
A range of combinators in `QCheck.Shrink` and `QCheck.Iter` are available
for building shrinking functions.
We can write a failing test using this generator to see the
printer and shrinker in action:
[source,OCaml]
----
let rec mirror_tree (t:tree) : tree = match t with
| Leaf _ -> t
| Node (a,b) -> node (mirror_tree b) (mirror_tree a);;
let test_buggy =
QCheck.Test.make ~name:"buggy_mirror" ~count:200
arbitrary_tree (fun t -> t = mirror_tree t);;
QCheck_runner.run_tests [test_buggy];;
----
This test fails with:
[source,OCaml]
----
--- Failure --------------------------------------------------------------------
Test mirror_buggy failed (6 shrink steps):
Node (Leaf 0,Leaf 1)
================================================================================
failure (1 tests failed, 0 tests errored, ran 1 tests)
- : int = 1
----
With the (new found) understanding that mirroring a tree
changes its structure, we can formulate another property
that involves sequentializing its elements in a traversal:
[source,OCaml]
----
let tree_infix (t:tree): int list =
let rec aux acc t = match t with
| Leaf i -> i :: acc
| Node (a,b) ->
aux (aux acc b) a
in
aux [] t;;
let test_mirror =
QCheck.Test.make ~name:"mirror_tree" ~count:200
arbitrary_tree
(fun t -> List.rev (tree_infix t) = tree_infix (mirror_tree t));;
QCheck_runner.run_tests [test_mirror];;
----
=== Preconditions
The functions `QCheck.assume` and `QCheck.(==>)` can be used for
tests with preconditions.
For instance, `List.hd l :: List.tl l = l` only holds for non-empty lists.
Without the precondition, the property is false and will even raise
an exception in some cases.
[source,OCaml]
----
let test_hd_tl =
QCheck.(Test.make
(list int) (fun l ->
assume (l <> []);
l = List.hd l :: List.tl l));;
QCheck_runner.run_tests [test_hd_tl];;
----
=== Long tests
It is often useful to have two version of a testsuite: a short one that runs
reasonably fast (so that it is effectively run each time a projet is built),
and a long one that might be more exhaustive (but whose running time makes it
impossible to run at each build). To that end, each test has a 'long' version.
In the long version of a test, the number of tests to run is multiplied by
the `~long_factor` argument of `QCheck.Test.make`.
=== Runners
The module `QCheck_runner` defines several functions to run tests, including
compatibility with `OUnit`.
The easiest one is probably `run_tests`, but if you write your tests in
a separate executable you can also use `run_tests_main` which parses
command line arguments and exits with `0` in case of success,
or an error number otherwise.
=== Integration within OUnit
http://ounit.forge.ocamlcore.org/[OUnit] is a popular unit-testing framework
for OCaml.
QCheck provides some helpers, in `QCheck_runner`, to convert its random tests
into OUnit tests that can be part of a wider test-suite.
[source,OCaml]
----
let passing =
QCheck.Test.make ~count:1000
~name:"list_rev_is_involutive"
QCheck.(list small_nat)
(fun l -> List.rev (List.rev l) = l);;
let failing =
QCheck.Test.make ~count:10
~name:"fail_sort_id"
QCheck.(list small_nat)
(fun l -> l = List.sort compare l);;
let _ =
let open OUnit in
run_test_tt_main
("tests" >:::
List.map QCheck_runner.to_ounit_test [passing; failing])
----
This diff is collapsed.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<link rel="stylesheet" href="style.css" type="text/css">
<meta content="text/html; charset=iso-8859-1" http-equiv="Content-Type">
<link rel="Start" href="index.html">
<link rel="previous" href="QCheck.Print.html">
<link rel="next" href="QCheck.Shrink.html">
<link rel="Up" href="QCheck.html">
<link title="Index of types" rel=Appendix href="index_types.html">
<link title="Index of exceptions" rel=Appendix href="index_exceptions.html">
<link title="Index of values" rel=Appendix href="index_values.html">
<link title="Index of modules" rel=Appendix href="index_modules.html">
<link title="QCheck" rel="Chapter" href="QCheck.html">
<link title="QCheck_runner" rel="Chapter" href="QCheck_runner.html"><title>QCheck.Iter</title>
</head>
<body>
<div class="navbar"><a class="pre" href="QCheck.Print.html" title="QCheck.Print">Previous</a>
&nbsp;<a class="up" href="QCheck.html" title="QCheck">Up</a>
&nbsp;<a class="post" href="QCheck.Shrink.html" title="QCheck.Shrink">Next</a>
</div>
<h1>Module <a href="type_QCheck.Iter.html">QCheck.Iter</a></h1>
<pre><span class="keyword">module</span> Iter: <code class="code">sig</code> <a href="QCheck.Iter.html">..</a> <code class="code">end</code></pre><div class="info module top">
<h2 id="2_Iterators">Iterators</h2>
<p>
Compatible with the library "sequence". An iterator <code class="code">i</code> is simply
a function that accepts another function <code class="code">f</code> (of type <code class="code">'a -&gt; unit</code>)
and calls <code class="code">f</code> on a sequence of elements <code class="code">f x1; f x2; ...; f xn</code>.<br>
</div>
<hr width="100%">
<pre><span id="TYPEt"><span class="keyword">type</span> <code class="type">'a</code> t</span> = <code class="type">('a -> unit) -> unit</code> </pre>
<pre><span id="VALempty"><span class="keyword">val</span> empty</span> : <code class="type">'a <a href="QCheck.Iter.html#TYPEt">t</a></code></pre>
<pre><span id="VALreturn"><span class="keyword">val</span> return</span> : <code class="type">'a -> 'a <a href="QCheck.Iter.html#TYPEt">t</a></code></pre>
<pre><span id="VAL(<*>)"><span class="keyword">val</span> (&lt;*&gt;)</span> : <code class="type">('a -> 'b) <a href="QCheck.Iter.html#TYPEt">t</a> -> 'a <a href="QCheck.Iter.html#TYPEt">t</a> -> 'b <a href="QCheck.Iter.html#TYPEt">t</a></code></pre>
<pre><span id="VAL(>>=)"><span class="keyword">val</span> (&gt;&gt;=)</span> : <code class="type">'a <a href="QCheck.Iter.html#TYPEt">t</a> -> ('a -> 'b <a href="QCheck.Iter.html#TYPEt">t</a>) -> 'b <a href="QCheck.Iter.html#TYPEt">t</a></code></pre>
<pre><span id="VALmap"><span class="keyword">val</span> map</span> : <code class="type">('a -> 'b) -> 'a <a href="QCheck.Iter.html#TYPEt">t</a> -> 'b <a href="QCheck.Iter.html#TYPEt">t</a></code></pre>
<pre><span id="VALmap2"><span class="keyword">val</span> map2</span> : <code class="type">('a -> 'b -> 'c) -> 'a <a href="QCheck.Iter.html#TYPEt">t</a> -> 'b <a href="QCheck.Iter.html#TYPEt">t</a> -> 'c <a href="QCheck.Iter.html#TYPEt">t</a></code></pre>
<pre><span id="VAL(>|=)"><span class="keyword">val</span> (&gt;|=)</span> : <code class="type">'a <a href="QCheck.Iter.html#TYPEt">t</a> -> ('a -> 'b) -> 'b <a href="QCheck.Iter.html#TYPEt">t</a></code></pre>
<pre><span id="VALappend"><span class="keyword">val</span> append</span> : <code class="type">'a <a href="QCheck.Iter.html#TYPEt">t</a> -> 'a <a href="QCheck.Iter.html#TYPEt">t</a> -> 'a <a href="QCheck.Iter.html#TYPEt">t</a></code></pre>
<pre><span id="VAL(<+>)"><span class="keyword">val</span> (&lt;+&gt;)</span> : <code class="type">'a <a href="QCheck.Iter.html#TYPEt">t</a> -> 'a <a href="QCheck.Iter.html#TYPEt">t</a> -> 'a <a href="QCheck.Iter.html#TYPEt">t</a></code></pre><div class="info ">
Synonym to <a href="QCheck.Iter.html#VALappend"><code class="code">QCheck.Iter.append</code></a><br>
</div>
<pre><span id="VALof_list"><span class="keyword">val</span> of_list</span> : <code class="type">'a list -> 'a <a href="QCheck.Iter.html#TYPEt">t</a></code></pre>
<pre><span id="VALof_array"><span class="keyword">val</span> of_array</span> : <code class="type">'a array -> 'a <a href="QCheck.Iter.html#TYPEt">t</a></code></pre>
<pre><span id="VALpair"><span class="keyword">val</span> pair</span> : <code class="type">'a <a href="QCheck.Iter.html#TYPEt">t</a> -> 'b <a href="QCheck.Iter.html#TYPEt">t</a> -> ('a * 'b) <a href="QCheck.Iter.html#TYPEt">t</a></code></pre>
<pre><span id="VALtriple"><span class="keyword">val</span> triple</span> : <code class="type">'a <a href="QCheck.Iter.html#TYPEt">t</a> -><br> 'b <a href="QCheck.Iter.html#TYPEt">t</a> -> 'c <a href="QCheck.Iter.html#TYPEt">t</a> -> ('a * 'b * 'c) <a href="QCheck.Iter.html#TYPEt">t</a></code></pre>
<pre><span id="VALquad"><span class="keyword">val</span> quad</span> : <code class="type">'a <a href="QCheck.Iter.html#TYPEt">t</a> -><br> 'b <a href="QCheck.Iter.html#TYPEt">t</a> -><br> 'c <a href="QCheck.Iter.html#TYPEt">t</a> -> 'd <a href="QCheck.Iter.html#TYPEt">t</a> -> ('a * 'b * 'c * 'd) <a href="QCheck.Iter.html#TYPEt">t</a></code></pre>
<pre><span id="VALfind"><span class="keyword">val</span> find</span> : <code class="type">('a -> bool) -> 'a <a href="QCheck.Iter.html#TYPEt">t</a> -> 'a option</code></pre></body></html>
\ No newline at end of file
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<link rel="stylesheet" href="style.css" type="text/css">
<meta content="text/html; charset=iso-8859-1" http-equiv="Content-Type">
<link rel="Start" href="index.html">
<link rel="previous" href="QCheck.Gen.html">
<link rel="next" href="QCheck.Iter.html">
<link rel="Up" href="QCheck.html">
<link title="Index of types" rel=Appendix href="index_types.html">
<link title="Index of exceptions" rel=Appendix href="index_exceptions.html">
<link title="Index of values" rel=Appendix href="index_values.html">
<link title="Index of modules" rel=Appendix href="index_modules.html">
<link title="QCheck" rel="Chapter" href="QCheck.html">
<link title="QCheck_runner" rel="Chapter" href="QCheck_runner.html"><title>QCheck.Print</title>
</head>
<body>
<div class="navbar"><a class="pre" href="QCheck.Gen.html" title="QCheck.Gen">Previous</a>
&nbsp;<a class="up" href="QCheck.html" title="QCheck">Up</a>
&nbsp;<a class="post" href="QCheck.Iter.html" title="QCheck.Iter">Next</a>
</div>
<h1>Module <a href="type_QCheck.Print.html">QCheck.Print</a></h1>
<pre><span class="keyword">module</span> Print: <code class="code">sig</code> <a href="QCheck.Print.html">..</a> <code class="code">end</code></pre><div class="info module top">
<h2 id="2_ShowValues">Show Values</h2><br>
</div>
<hr width="100%">
<pre><span id="TYPEt"><span class="keyword">type</span> <code class="type">'a</code> t</span> = <code class="type">'a -> string</code> </pre>
<pre><span id="VALint"><span class="keyword">val</span> int</span> : <code class="type">int <a href="QCheck.Print.html#TYPEt">t</a></code></pre>
<pre><span id="VALbool"><span class="keyword">val</span> bool</span> : <code class="type">bool <a href="QCheck.Print.html#TYPEt">t</a></code></pre>
<pre><span id="VALfloat"><span class="keyword">val</span> float</span> : <code class="type">float <a href="QCheck.Print.html#TYPEt">t</a></code></pre>
<pre><span id="VALchar"><span class="keyword">val</span> char</span> : <code class="type">char <a href="QCheck.Print.html#TYPEt">t</a></code></pre>
<pre><span id="VALstring"><span class="keyword">val</span> string</span> : <code class="type">string <a href="QCheck.Print.html#TYPEt">t</a></code></pre>
<pre><span id="VALoption"><span class="keyword">val</span> option</span> : <code class="type">'a <a href="QCheck.Print.html#TYPEt">t</a> -> 'a option <a href="QCheck.Print.html#TYPEt">t</a></code></pre>
<pre><span id="VALpair"><span class="keyword">val</span> pair</span> : <code class="type">'a <a href="QCheck.Print.html#TYPEt">t</a> -> 'b <a href="QCheck.Print.html#TYPEt">t</a> -> ('a * 'b) <a href="QCheck.Print.html#TYPEt">t</a></code></pre>
<pre><span id="VALtriple"><span class="keyword">val</span> triple</span> : <code class="type">'a <a href="QCheck.Print.html#TYPEt">t</a> -><br> 'b <a href="QCheck.Print.html#TYPEt">t</a> -> 'c <a href="QCheck.Print.html#TYPEt">t</a> -> ('a * 'b * 'c) <a href="QCheck.Print.html#TYPEt">t</a></code></pre>
<pre><span id="VALquad"><span class="keyword">val</span> quad</span> : <code class="type">'a <a href="QCheck.Print.html#TYPEt">t</a> -><br> 'b <a href="QCheck.Print.html#TYPEt">t</a> -><br> 'c <a href="QCheck.Print.html#TYPEt">t</a> -> 'd <a href="QCheck.Print.html#TYPEt">t</a> -> ('a * 'b * 'c * 'd) <a href="QCheck.Print.html#TYPEt">t</a></code></pre>
<pre><span id="VALlist"><span class="keyword">val</span> list</span> : <code class="type">'a <a href="QCheck.Print.html#TYPEt">t</a> -> 'a list <a href="QCheck.Print.html#TYPEt">t</a></code></pre>
<pre><span id="VALarray"><span class="keyword">val</span> array</span> : <code class="type">'a <a href="QCheck.Print.html#TYPEt">t</a> -> 'a array <a href="QCheck.Print.html#TYPEt">t</a></code></pre>
<pre><span id="VALcomap"><span class="keyword">val</span> comap</span> : <code class="type">('a -> 'b) -> 'b <a href="QCheck.Print.html#TYPEt">t</a> -> 'a <a href="QCheck.Print.html#TYPEt">t</a></code></pre></body></html>
\ No newline at end of file