[m-rev.] for review: extras/quickcheck/tutes/*.html fixes
Peter Moulder
pmoulder at csse.monash.edu.au
Fri Feb 22 15:07:38 AEDT 2002
The attached diff uses the `-w' flag for ease of reading. Many lines
have whitespace changes, partly because I ran all files through
`expand'. (Rationale for expanding tabs: tab stops aren't guaranteed
to be the same across web browsers, which is relevant inside <pre>.)
I've inserted DTD headers according to what `tidy' determined, which
ranged from HTML 2.0 to HTML 4.01. (I think the table summary
attribute is the only HTML 4 thing used.)
I don't have commit rights, but I'll get David Overton to commit once
approved. Please cc me in replies, I'm not subscribed to
mercury-reviews.
pjm.
Estimated hours taken: 2
Many HTML fixes. (Previously there were enough problems that it made
more sense to read them as plain text files than with a web browser.)
The files now pass through weblint (cleanly) and tidy (only `table
lacks "summary" attribute' warnings remain).
A small number of textual changes, and also a couple of <!-- XXX
... --> comments where I suspect the text should be changed.
Only the extras/quickcheck/tutes/*.html files are affected by this
diff.
Index: T1.html
===================================================================
RCS file: /home/mercury1/repository/mercury/extras/quickcheck/tutes/T1.html,v
retrieving revision 1.2
diff -d -u -w -r1.2 T1.html
--- T1.html 3 Oct 2001 02:04:08 -0000 1.2
+++ T1.html 22 Feb 2002 03:52:12 -0000
@@ -1,38 +1,43 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
<html>
<head>
- <TITLE> QuickCheck </TITLE>
+<title>QuickCheck</title>
</head>
+<body>
Files :
<a href="use.m">use.m</a>
<a href="use1.m">use1.m</a>
<a href="use11.m">use11.m</a>
<a href="nrev.m">nrev.m</a>
-<a href="nrev2.m">nrev2.m</a><BR>
+<a href="nrev2.m">nrev2.m</a>
+<br>
<a href="index.html">Back to main</a>
-<H1> QuickCheck Tutorial 1 </H1>
-
+<h1>QuickCheck Tutorial 1</h1>
-<pre>
-Quickcheck is a tool which aids the Mercury programmer in formulating and
+<p>
+Quickcheck is a tool that aids the Mercury programmer in formulating and
testing properties of programs. The programmer must supply invariant
functions which test certain properties of the programs. Those invariant
functions can then be automatically tested on random inputs. It is
possible to alter the test data distribution or define a custom test
data generator.
+<p>
In order to test the validity of a predicate/function via quickcheck,
you need the following components :
- qcheck.m -- quickcheck module (supplied)
- rnd.m -- required by quickcheck module (supplied)
- XXX.m -- module containing the predicate/function
- the user is trying to validate
- YYY.m -- main module, which calls qcheck/4
+<dl>
+<dt>qcheck.m <dd>quickcheck module (supplied)
+<dt>rnd.m <dd>required by quickcheck module (supplied)
+<dt>XXX.m <dd>module containing the predicate/function the user is trying to validate
+<dt>YYY.m <dd>main module, which calls <code>qcheck</code>/4.
+</dl>
-A Simple Example
-Let XXX.m be "nrev.m", which contains nrev/1 :
-<P>
-<table border=0 width=100% bgcolor=#eeeee0><tr><td><pre>
+<h2>A Simple Example</h2>
+
+<p>Let XXX.m be "nrev.m", which contains nrev/1:
+
+<table border=0 width="100%" bgcolor="#eeeee0"><tr><td><pre>
:- func nrev(list(T)) = list(T).
:- mode nrev(in) = out is det.
nrev([]) = [].
@@ -41,38 +46,43 @@
</pre></tr></table>
We want to test whether nrev/1 is properly implemented.
+<p>
Let YYY.m be "use.m". It must contain a main/2, and an
invariant function. If nrev/1 is correctly implemented then it
should satisfy the following rules:
-<H4>
+<pre>
reverse [x] = [x]
- reverse (xs+ys) = reverse ys + reverse xs
+ reverse (xs ++ ys) = reverse(ys) ++ reverse(xs)
reverse (reverse xs) = xs
-</H4>
+</pre>
+
+<p>
To test whether 2nd rule holds for nrev/1, define the invariant
function as :
-<H4>
+<pre>
testing(Xs, Ys) =
nrev(Xs ++ Ys) `===` (nrev(Ys) ++ nrev(Xs)).
-</H4>
+</pre>
+
+<p>
`===` function returns 'property:[yes]' if the left side equals
right side, 'property:[no]' otherwise.
In theory nrev/1 can take a list(T), however in order for
quickcheck to automatically generate Xs and Ys, the programmer must
-specify a fixed type at which the law is to be tested, eg:
-<H4>
+specify a fixed type for which the law is to be tested, eg:
+<pre>
:- func testing(list(int), list(int)) = property.
Or
:- func testing(list(char), list(char)) = property.
-</H4>
+</pre>
Now define the main/2 as
-<H4>
- main --- >
- qcheck(qcheck_f(testing), "sample testing").
-</H4>
+<pre>
+ main -->
+ qcheck(qcheck__f(testing), "sample testing").
+</pre>
The complete use.m looks like this:
-<P>
-<table border=0 width=100% bgcolor=#eeeee0><tr><td><pre>
+
+<table border=0 width="100%" bgcolor="#eeeee0"><tr><td><pre>
:- module use.
@@ -92,7 +102,7 @@
%-------------------------------------------------------------------%
-main -->
+main -->
qcheck(qcheck__f(testing), "sample testing").
%-------------------------------------------------------------------%
@@ -105,31 +115,33 @@
</pre></tr></table>
To compile the program, do "mmake use.depend", then "mmake use".
After running, the statistics should be displayed like :
-<H4>
+<pre>
Test Description : sample testing
Number of test cases that succeeded : 100
Number of trivial tests : 0
Number of tests cases which failed the pre-condition : 0
Distributions of selected argument(s) :
-</H4>
+</pre>
nrev/1 passed 100 tests and failed none (ignore the last 3 lines
for now).
+<p>
If the invariant function is wrongly specified, or nrev/1 is not
properly implemented, then the statistics may look like :
-<H4>
+<pre>
Test description : sample testing
Falsifiable :
[2]
[-2, 1]
-</H4>
+</pre>
where running [2] as Xs and [-2, 1] as Ys failed the invariant function.
+<p>
Defining an invariant function which contains only functions is more
concise than one which contains predicates. Suppose that "nrev2.m"
defines a predicate version of reversing list:
-<P>
-<table border=0 width=100% bgcolor=#eeeee0><tr><td><pre>
+
+<table border=0 width="100%" bgcolor="#eeeee0"><tr><td><pre>
:- pred nrev2(list(T), list(T)).
:- mode nrev2(in, out) is det.
nrev2([], []).
@@ -138,17 +150,17 @@
list__append(Reversed, [X], Ys).
</pre></tr></table>
Then the invariant function looks like :
-<h4>
+<pre>
testing2(Xs, Ys) = (Left `===` Right) :-
nrev2((Xs ++ Ys), Left),
nrev2(Ys, Part_a),
nrev2(Ys, Part_b),
Right = Part_a ++ Part_b.
-</h4>
+</pre>
Above code is effectively the same as testing/2, however it requires a few extra
lines to extract the intermediate values, (use1.m) :
-<P>
-<table border=0 width=100% bgcolor=#eeeee0><tr><td><pre>
+
+<table border=0 width="100%" bgcolor="#eeeee0"><tr><td><pre>
:- module use1.
:- interface.
@@ -167,7 +179,7 @@
%-------------------------------------------------------------------%
-main -->
+main -->
qcheck(qcheck__f(testing2), "testing2").
%-------------------------------------------------------------------%
@@ -183,10 +195,10 @@
</pre></tr></table>
An alternative to writing a separate invariant function is to
use Mercury's syntax for higher order terms. When doing this,
-the `with_type` operator can be useful to provide fixed types
+the <code>`with_type`</code> operator can be useful to provide fixed types
for the arguments of the invariant function. For example (use11.m):
-<P>
-<table border=0 width=100% bgcolor=#eeeee0><tr><td><pre>
+
+<table border=0 width="100%" bgcolor="#eeeee0"><tr><td><pre>
:- module use11.
:- interface.
@@ -205,41 +217,47 @@
%--------------------------------------------------------------------------%
-main -->
+main -->
qcheck(qcheck__f(func(Xs `with_type` list(int), Ys `with_type` list(int))
= nrev(Xs ++ Ys) `===` (nrev(Ys) ++ nrev(Xs))),
"sample testing").
</pre></tr></table>
+<p>
In YYY.m, the main/2 should be defined as :
-<h4>
- main --->
- qcheck(qcheck_f(Invariant_Function_X), Test_Desc_Y).
-</h4>
+<pre>
+ main -->
+ qcheck(qcheck__f(Invariant_Function_X), Test_Desc_Y).
+</pre>
Where Invariant_Function_X is a higher order term (function) and
Test_Desc_Y is a string which describe/name/comment Invariant_Function_X.
+<p>
The invariant function is of the form
-<h4>
+<pre>
:- mode Invariant_Function_X(in, in, in ...) = out.
-</h4>
+</pre>
The invariant function can only take 0 to 10 arguments, but the inputs can
be of any type. All invariant functions must return a property, which is just
a list of flags.
-<P>
-<table border=0 width=100% bgcolor=#eeeee0><tr><td><pre>
+
+<table border=0 width="100%" bgcolor="#eeeee0"><tr><td><pre>
:- type property == list(flag).
:- type flag
- ---> yes
+ ---> yes
; no
; trivial
; info(univ)
; condition.
</pre></tr></table>
-What ever happens inside Invariant_Function_X, quickcheck does not care. If
-the output does not contain 'flag:no' the invariant function is assumed to
+
+<p>QuickCheck does not care what happens inside Invariant_Function_X. If
+the output does not contain 'flag:no', the invariant function is assumed to
pass the testcase satisfactory.
-<a href="T4.html">Click here to get the details on each individual flag.</a>
+<p>See <a href="T4.html">part 4 of the tutorial</a> to get the details
+on each individual flag.
+
+</body>
</html>
Index: T10.html
===================================================================
RCS file: /home/mercury1/repository/mercury/extras/quickcheck/tutes/T10.html,v
retrieving revision 1.2
diff -d -u -w -r1.2 T10.html
--- T10.html 3 Oct 2001 02:04:08 -0000 1.2
+++ T10.html 22 Feb 2002 03:52:12 -0000
@@ -1,54 +1,96 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
<html>
<head>
- <TITLE> QuickCheck </TITLE>
+<title>QuickCheck</title>
</head>
+<body>
<a href="index.html">Back to main</a>
-<H1> QuickCheck Tutorial 10 </H1>
-<h3> Summary - Generators </h3>
-<pre>
-Quickcheck is able to generate random values for each input
+<h1>QuickCheck Tutorial 10</h1>
+
+<h2>Summary - Generators</h2>
+
+<p>
+QuickCheck is able to generate random values for each input
argument at run time, provided that there is a default/custom
generator for that type. The master seed for randomness is the
current time.
-Quickcheck generates value via the following steps:
+<p>QuickCheck generates values via the following steps:
- 1 The master generator is called with 7 arguments.
- Arg1 type_desc of the required term
- Arg2 SF for the current term
- Arg3 a list of all GF
- Arg4 a list of all custom generators
- Arg5 ouputs a univ of the generated term
- Arg6 random number supply input
- Arg7 random number supply output
+<table>
+<tr>
+<td>1</td>
+<td>The master generator is called with 7 arguments:
+ <table>
+ <tr>
+ <td>Arg1</td> <td><code>type_desc</code> of the required term</td>
+ </tr>
+ <tr>
+ <td>Arg2</td> <td>SF for the current term</td>
+ </tr>
+ <tr>
+ <td>Arg3</td> <td>a list of all GF</td>
+ </tr>
+ <tr>
+ <td>Arg4</td> <td>a list of all custom generators</td>
+ </tr>
+ <tr>
+ <td>Arg5</td> <td>ouputs a univ of the generated term </td>
+ </tr>
+ <tr>
+ <td>Arg6</td> <td>random number supply input</td>
+ </tr>
+ <tr>
+ <td>Arg7</td> <td>random number supply output</td>
+ </tr>
+ </table>
+</td>
+</tr>
- 2a Quickcheck searches through the list of custom generators,
+<tr>
+ <td>2a</td>
+ <td>QuickCheck searches through the list of custom generators,
if there is a custum generator for the current term, then
call the custom generator with Arg1, 2, 3, 4, 6, 7.
The master generator will return what ever is returned by the
- custom generator.
-
- 2b If Quickcheck fails to locate a custom generator, then it will
+ custom generator.</td>
+</tr>
+<tr>
+ <td>2b</td>
+ <td>If QuickCheck fails to locate a custom generator, then it will
classify the current term as of type int, char, float, string,
- discriminated union, and other.
-
- 3b1 If it's type int, call rand_int/2 with Arg6 and Arg7
-
- 3b2 If it's type char, call rand_char/2 with Arg6 and Arg7
-
- 3b3 If it's type float, call rand_float/2 with Arg6 and Arg7
-
- 3b4 If it's type string, call rand_string/2 with Arg6 and Arg8
-
- 3b5 If it's type discriminated union, call rand_union/6 with
- Arg1, Arg2, Arg3, Arg4, Arg6, Arg7.
-
- 3b6 If it's classified as other, then call rand_function with Arg1,
+ discriminated union, and other.</td>
+</tr>
+<tr>
+ <td>3b1</td>
+ <td>If it's type int, call rand_int/2 with Arg6 and Arg7</td>
+</tr>
+<tr>
+ <td>3b2</td>
+ <td>If it's type char, call rand_char/2 with Arg6 and Arg7</td>
+</tr>
+<tr>
+ <td>3b3</td>
+ <td>If it's type float, call rand_float/2 with Arg6 and Arg7</td>
+</tr>
+<tr>
+ <td>3b4</td>
+ <td>If it's type string, call rand_string/2 with Arg6 and Arg8</td>
+</tr>
+<tr>
+ <td>3b5</td>
+ <td>If it's type discriminated union, call rand_union/6 with
+ Arg1, Arg2, Arg3, Arg4, Arg6, Arg7.</td>
+</tr>
+<tr>
+ <td>3b6</td>
+ <td>If it's classified as other, then call rand_function with Arg1,
Arg6 and Arg7. Quickcheck will generates the appropriate value if
Arg1 is of a function with arity 0 to 10. Otherwise an error will
- be thrown :
- "no default generator for this type"
-
-
+ be thrown: "no default generator for this type".</td>
+</tr>
+</table>
+</body>
+</html>
Index: T2.html
===================================================================
RCS file: /home/mercury1/repository/mercury/extras/quickcheck/tutes/T2.html,v
retrieving revision 1.1
diff -d -u -w -r1.1 T2.html
--- T2.html 31 May 2001 02:08:47 -0000 1.1
+++ T2.html 22 Feb 2002 03:52:12 -0000
@@ -1,47 +1,57 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
- <TITLE> QuickCheck </TITLE>
+<title>QuickCheck</title>
</head>
-<H1> QuickCheck Tutorial 2 </H1>
+<body>
+<h1>QuickCheck Tutorial 2</h1>
+
+<p>
Files :
<a href="use20.m">use20.m</a>
<a href="use21.m">use21.m</a>
<a href="use22.m">use22.m</a>
-<a href="mymax.m">mymax.m</a><BR>
+<a href="mymax.m">mymax.m</a>
+<br>
<a href="index.html">Back to main</a>
-<h3> Conditional law </h3>
-<pre>
+<h2>Conditional law</h2>
+
+<p>
In general many laws hold only under certain conditions. Quickcheck provides
an implication combinator to represent such conditional laws. Eg, the law
- X =< Y => max x y == y
+<pre>
+ X =< Y => max x y == y
+</pre>
can be represented by the definition :
-<h4>
+<pre>
:- func law(int, int) = property.
- law(X, Y) = (X =< Y) `===>` (mymax(X, Y) `===` Y).
-</h4>
+ law(X, Y) = (X =< Y) `===>` (mymax(X, Y) `===` Y).
+</pre>
or alternatively can be represented as :
-<h4>
+<pre>
:- func law2(int, int) = property.
- law2(X, Y) = is_less_equal(X, Y) `===>` (mymax(X, Y) `===` Y).
+ law2(X, Y) = is_less_equal(X, Y) `===>` (mymax(X, Y) `===` Y).
:- func is_less_equal(int, int) = bool.
is_less_equal(X, Y) = Bool :-
- (if X =< Y
+ (if X =< Y
then
Bool = yes
else
Bool = no
).
-</h4>
-The difference between law1 and law2 is the left argument of `===>`.
-(X =< Y) is type (pred) and is_less_equal(X, Y) returns type bool.
-`===>` is overloaded to take both types.
+</pre>
+The difference between law1 and law2 is the left argument of `===>`.
+<samp>(X =< Y)</samp> is of type (pred) whereas
+<samp>is_less_equal(X, Y)</samp> evaluates to type bool.
+`===>` is overloaded to take both types.
+<p>
The complete use20.m :
-<P>
-<table border=0 width=100% bgcolor=#eeeee0><tr><td><pre>
+
+<table border=0 width="100%" bgcolor="#eeeee0" summary="use20.m source code"><tr><td><pre>
:- module use20.
:- interface.
@@ -60,20 +70,20 @@
%---------------------------------------------------------------------------%
-main -->
- qcheck(qcheck__f(law), "testing mymax using `===>` for (pred)"),
- qcheck(qcheck__f(law2), "testing mymax using `===>` for bool").
+main -->
+ qcheck(qcheck__f(law), "testing mymax using `===>` for (pred)"),
+ qcheck(qcheck__f(law2), "testing mymax using `===>` for bool").
:- func law(int, int) = property.
-law(X, Y) = (X =< Y) `===>` (mymax(X, Y) `===` Y).
+law(X, Y) = (X =< Y) `===>` (mymax(X, Y) `===` Y).
:- func law2(int, int) = property.
-law2(X, Y) = is_less_equal(X, Y) `===>`
+law2(X, Y) = is_less_equal(X, Y) `===>`
(mymax(X, Y) `===` Y).
:- func is_less_equal(int, int) = bool.
is_less_equal(X, Y) = Bool :-
- (if X =< Y
+ (if X =< Y
then
Bool = yes
else
@@ -81,42 +91,45 @@
).
</pre></tr></table>
After running the program, test statistics will be something like:
-<h4>
- Test Description : testing mymax using `===>` for (pred)
+<pre>
+ Test Description : testing mymax using `===>` for (pred)
Number of test cases that succeeded : 52
Number of trivial tests : 0
Number of tests cases which failed the pre-condition : 48
Distributions of selected argument(s) :
- Test Description : testing mymax using `===>` for bool
+ Test Description : testing mymax using `===>` for bool
Number of test cases that succeeded : 52
Number of trivial tests : 0
Number of tests cases which failed the pre-condition : 48
Distributions of selected argument(s) :
-</h4>
+</pre>
The default number of tests to run is 100. In the above test, 48/100 cases
passed the invariant function, and none failed. However, there are 52/100
cases where the inputs failed the pre-condition.
+<p>
Note that both test cases succeeded 52/100 and failed pre-condition 48/100.
qcheck.m seeds the random generator on local time, if qcheck is called twice
within the same second, the number generated will be the same.
+<p>
The implication combinator can be compounded. For example, suppose mymax is
designed that if mymax(X, Y) is called, Y will never be zero. Thus test cases
with Y=0 should also be disregarded (use21.m) :
-<h4>
+<pre>
:- func law(int, int) = property.
- law(X, Y) = notzero(Y) `===>` ((X =< Y) `===>` (mymax(X, Y) `===` Y)).
+ law(X, Y) = notzero(Y) `===>` ((X =< Y) `===>` (mymax(X, Y) `===` Y)).
:- pred notzero(int).
:- mode notzero(in) is semidet.
notzero(X) :- X \= 0.
-</h4>
+</pre>
-The right argument of `===>` is also overload, as shown in use22.m :
-<P>
-<table border=0 width=100% bgcolor=#eeeee0><tr><td><pre>
+<p>
+The right argument of `===>` is also overload, as shown in use22.m:
+
+<table border=0 width="100%" bgcolor="#eeeee0" summary="use22.m source code"><tr><td><pre>
:- module use22.
:- interface.
@@ -135,30 +148,31 @@
%---------------------------------------------------------------------------%
-main -->
+main -->
qcheck(qcheck__f(law1), "passing property"),
qcheck(qcheck__f(law2), "passing (func) = property").
:- func law1(int, int) = property.
-law1(X, Y) = notzero(Y) `===>` qcheck__f( (func) = ((X // Y) `===` (X // Y)) ).
+law1(X, Y) = notzero(Y) `===>` qcheck__f( (func) = ((X // Y) `===` (X // Y)) ).
:- func law2(int, int) = property.
-law2(X, Y) = notzero(Y) `===>` ( (X // Y) `===` (X // Y) ).
+law2(X, Y) = notzero(Y) `===>` ( (X // Y) `===` (X // Y) ).
:- pred notzero(int).
:- mode notzero(in) is semidet.
notzero(X) :- X \= 0.
</pre></tr></table>
-The difference between law1/2 and law2/2 is the right argument of `===>`.
+The difference between law1/2 and law2/2 is the right argument of `===>`.
law1/2 passed (func), while law2/2 passed property. In law2/2, (X // Y) is
always evaluated, which will cause error if Y is zero. However, in law1/2
-(X // Y) is not evaluated if `===>`'s left argument is 'bool:no' or
+(X // Y) is not evaluated if `===>`'s left argument is 'bool:no' or
'(pred):failure'.
-The implication combinator '===>' marks a test that has failed pre-condition
+<p>The implication combinator `===>` marks a test that has failed pre-condition
by inserting 'flag:condition' into the property in cases where the right
argument is a property; in cases where the right argument is (func), then
-`===>` will just return 'property:[condition]'.
+`===>` will just return 'property:[condition]'.
If the property list contains one or more 'condition', the test result is
ignored.
+</body>
</html>
Index: T3.html
===================================================================
RCS file: /home/mercury1/repository/mercury/extras/quickcheck/tutes/T3.html,v
retrieving revision 1.2
diff -d -u -w -r1.2 T3.html
--- T3.html 3 Oct 2001 02:04:08 -0000 1.2
+++ T3.html 22 Feb 2002 03:52:12 -0000
@@ -1,49 +1,58 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
- <TITLE> QuickCheck </TITLE>
+<title>QuickCheck</title>
</head>
-<H1> QuickCheck Tutorial 3 </H1>
+<body>
+<p>
Files :
<a href="use31.m">use31.m</a>
<a href="use33.m">use33.m</a>
-<a href="nrev.m">nrev.m</a><BR>
+<a href="nrev.m">nrev.m</a>
+<br>
<a href="index.html">Back to main</a>
-<h3> Monitoring Test Data - to_trivial/3 </h3>
-<pre>
+<h1>QuickCheck Tutorial 3</h1>
+<h2>Monitoring Test Data: <code>to_trivial/3</code></h2>
+
+<p>
In Tutorial 1, the 3rd rule for reverse is that:
+<pre>
reverse (reverse xs) = xs
-It's not much of a test if xs is empty list or list with only 1 element.
+</pre>
+It's not much of a test if <code>xs</code> is an empty list or a list with only 1 element.
+<p>
Quickcheck can label a test being trivial via the function
to_trivial/3, which does not change the meaning of a law, but it classifies
-some of the test cases. Without classifying the invariant function could be :
-<h4>
+some of the test cases.
+Without classifying, the invariant function could be:
+<pre>
:- func testing1(list(float)) = property.
testing1(Xs) =
nrev (nrev Xs) `===` Xs.
-</h4>
+</pre>
If the 1st argument of to_trivial/3 is equal to the 2nd argument, then that test
-case will be labeled trivial by pushing flag:trivial into the third argument
+case will be labeled trivial by pushing <code>flag:trivial</code> into the third argument
( which is a list of flags ).
testing2/1 treats empty list as trivial test.
-<h4>
+<pre>
:- func testing2(list(float)) = property.
testing2(Xs) =
to_trivial([], Xs, nrev (nrev Xs) `===` Xs).
-</h4>
-Use compounded to_trivial to also classify list of 1 element as trivial
-<h4>
+</pre>
+Use compounded to_trivial to also classify lists of 1 element as trivial
+<pre>
:- func testing3(list(float)) = property.
testing3(Xs) =
to_trivial(1,
list_length(Xs),
to_trivial([], Xs, nrev(nrev(Xs)) `===` Xs)
).
-</h4>
+</pre>
The complete code (use31.m) :
-<P>
-<table border=0 width=100% bgcolor=#eeeee0><tr><td><pre>
+
+<table border=0 width="100%" bgcolor="#eeeee0" summary="use31.m source code"><tr><td><pre>
:- module use31.
:- interface.
@@ -62,7 +71,7 @@
%---------------------------------------------------------------------------%
-main -->
+main -->
qcheck(qcheck__f(testing1), "testing1"),
qcheck(qcheck__f(testing2), "testing2"),
qcheck(qcheck__f(testing3), "testing3").
@@ -83,7 +92,7 @@
).
</pre></tr></table>
A sample output :
-<h4>
+<pre>
Test Description : testing1
Number of test cases that succeeded : 100
Number of trivial tests : 0
@@ -101,28 +110,32 @@
Number of trivial tests : 75
Number of tests cases which failed the pre-condition : 0
Distributions of selected argument(s) :
-</h4>
+</pre>
Note test1, the original, has no trivial cases. With test2, 53/100 tests have
an empty list as its input. Test3 shows 75/100 tests have either an empty list
or a list of only one element. It only tested 25/100 cases where the list is
longer than 1 element.
-<h3> Monitoring Test Data - `>>>` </h3>
-The combinator `>>>` gathers all values that are passed to it, and prints out
+<h2>Monitoring Test Data: <code>`>>>`</code></h2>
+
+<p>The combinator <code>`>>>`</code> gathers all values that are
+passed to it, and prints out
a histogram of these values.
-Let's use `>>>` to find out exactly what lists are generated for the previous
+Let's use <code>`>>>`</code> to find out exactly what lists are generated for the previous
tests :
-<h4>
+<pre>
:- func testing4(list(float)) = property.
testing4(Xs) =
- list_length(Xs) `>>>` (nrev(nrev(Xs)) `===` Xs).
-</h4>
-The combinator `>>>` will convert its left argument to a univ, and push
-info(univ) into the property list.
-The complete code (use31.m) :
-<P>
-<table border=0 width=100% bgcolor=#eeeee0><tr><td><pre>
+ list_length(Xs) `>>>` (nrev(nrev(Xs)) `===` Xs).
+</pre>
+
+<p>The combinator <code>`>>>`</code> will convert its left
+argument to a univ, and push info(univ) into the property list.
+
+<p>The complete code (use31.m):
+
+<table border=0 width="100%" bgcolor="#eeeee0" summary="use31.m source code"><tr><td><pre>
:- module use31.
:- interface.
@@ -141,7 +154,7 @@
%---------------------------------------------------------------------------%
-main -->
+main -->
qcheck(qcheck__f(testing1), "testing1"),
qcheck(qcheck__f(testing2), "testing2"),
qcheck(qcheck__f(testing3), "testing3"),
@@ -164,10 +177,10 @@
:- func testing4(list(float)) = property.
testing4(Xs) =
- list_length(Xs) `>>>` (nrev(nrev(Xs)) `===` Xs).
+ list_length(Xs) `>>>` (nrev(nrev(Xs)) `===` Xs).
</pre></tr></table>
A sample output :
-<h4>
+<pre>
Test Description : testing1
Number of test cases that succeeded : 100
Number of trivial tests : 0
@@ -199,7 +212,7 @@
16 2
18 1
53 0
-</h4>
+</pre>
The display of testing4 shows that 53 cases of length == 0
18 cases of length == 1
16 cases of length == 2
@@ -209,10 +222,10 @@
the same random number seed.
-The value passed to `>>>` does not have to be the same type, and `>>>` can
-be compounded like to_trivial/3, eg (use33.m):
-<P>
-<table border=0 width=100% bgcolor=#eeeee0><tr><td><pre>
+The value passed to `>>>` does not have to be the same type, and `>>>` can
+be compounded like to_trivial/3, e.g. (use33.m):
+
+<table border=0 width="100%" bgcolor="#eeeee0" summary="use33.m source code"><tr><td><pre>
:- module use33.
:- interface.
@@ -231,13 +244,13 @@
%---------------------------------------------------------------------------%
-main -->
+main -->
qcheck(qcheck__f(testing5), "testing5").
:- func testing5(list(float)) = property.
testing5(Xs) =
- odd_even(Xs) `>>>`
- (list_length(Xs) `>>>` (nrev(nrev(Xs)) `===` Xs)).
+ odd_even(Xs) `>>>`
+ (list_length(Xs) `>>>` (nrev(nrev(Xs)) `===` Xs)).
:- func odd_even(list(T)) = string.
:- mode odd_even(in) = out is det.
@@ -251,7 +264,7 @@
</pre></tr></table>
testing5 collects the list_length, and also collect "odd" or "even"
A sample output :
-<h4>
+<pre>
Test Description : testing5
Number of test cases that succeeded : 100
Number of trivial tests : 0
@@ -267,7 +280,8 @@
39 "odd"
47 0
61 "even"
-</h4>
+</pre>
+</body>
</html>
Index: T4.html
===================================================================
RCS file: /home/mercury1/repository/mercury/extras/quickcheck/tutes/T4.html,v
retrieving revision 1.2
diff -d -u -w -r1.2 T4.html
--- T4.html 3 Oct 2001 02:04:08 -0000 1.2
+++ T4.html 22 Feb 2002 03:52:12 -0000
@@ -1,78 +1,88 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
- <TITLE> QuickCheck </TITLE>
+<title>QuickCheck</title>
</head>
-<H1> QuickCheck Tutorial 4 </H1>
-
+<body>
<a href="index.html">Back to main</a>
-<h3> Summary - Invariant Function & Property </h3>
-<pre>
+<h1>QuickCheck Tutorial 4</h1>
+
+<h2>Summary - Invariant Function & Property</h2>
+
+<p>
The invariant function is of the form
+<pre>
:- func Invariant_Function_X(T, T1, T2 ...) = property
:- mode Invariant_Function_X(in, in, in ...) = out.
-The inputs can be of most types (details next tutorial), however only arity
-0 to 10 are implemented. The output must be property, defined as :
-<P>
-<table border=0 width=100% bgcolor=#eeeee0><tr><td><pre>
+</pre>
+
+<p>
+The inputs can be of most types (details next tutorial), but only arities
+0 to 10 are implemented. The output must be of type <code>property</code>, defined as:
+
+<table border=0 width="100%" bgcolor="#eeeee0" summary="Type definitions of flag and property."><tr><td><pre>
:- type property == list(flag).
:- type flag
- ---> yes
+ ---> yes
; no
; trivial
; info(univ)
; condition.
</pre></tr></table>
-What ever happens inside Invariant_Function_X, quickcheck does not care; it only
+
+<p>QuickCheck does not care what happens inside Invariant_Function_X; it only
looks at the output property. Any form of property is valid, in the sense that
the qcheck will not abort. However not all forms of property is sensible.
One could return [], or [yes, no, yes, no]. Quickcheck analyzes the property in
the following order:
- 1 Firstly, qcheck determines whether the invariant function has
+<ol>
+ <li> Firstly, qcheck determines whether the invariant function has
failed. This only occurs if the property list contains at least
one 'flag:no' and does not contain 'flag:condition'. In this
case the NOFLAG will be switched to 'bool:yes', and the message
"Falsifiable ... ..." is printed. Otherwise move to step 2.
- 2 qcheck will then test if the 'condition' flag (1 or more) is
+ <li> qcheck will then test if the 'condition' flag (1 or more) is
in the property list. If it is, then the FAILEDCONDITION counter
is incremented and stops analyzing. If the 'condition' flag is
not within the property list, then move to step 3.
- 3 qcheck increments the YES counter.
- 4 qcheck increments the TRIVIAL counter if it finds the 'trivial'
+ <li> qcheck increments the YES counter.
+ <li> qcheck increments the TRIVIAL counter if it finds the 'trivial'
flag (1 or more) is within the list.
- 5 Then qcheck gets all the info(univ) (if any) in the list and
+ <li> Then qcheck gets all the info(univ) (if any) in the list and
merge that with the master list for distribution.
+</ol>
So, [] will increase the YES counter, and [yes, no, yes, no] will switch the
NOFLAG counter.
-<P>
-<table border=0 width=100% bgcolor=#eeeee0><tr><td><pre>
+
+<table border=0 width="100%" bgcolor="#eeeee0"><tr><td><pre>
:- func T `===` T = property.
:- mode in `===` in = out is det.
Left `===` Right Left == Right return [yes]
Left != Right return [no]
-:- func (pred) `===>` property = property.
-:- mode in((pred) is semidet) `===>` in = out is det.
-Left `===>` Right Left fails return [condition | Right]
+:- func (pred) `===>` property = property.
+:- mode in((pred) is semidet) `===>` in = out is det.
+Left `===>` Right Left fails return [condition | Right]
Left succeeds return Right
-:- func bool `===>` property = property.
-:- mode in `===>` in = out is det.
-Left `===>` Right Left == no return [condition | Right]
+:- func bool `===>` property = property.
+:- mode in `===>` in = out is det.
+Left `===>` Right Left == no return [condition | Right]
Left == yes return Right
Note: :- type f0
- ---> f((func) = property).
+ ---> f((func) = property).
-:- func (pred) `===>` f0 = property.
-:- mode in((pred) is semidet) `===>` in = out is det.
-Left `===>` Right Left fails return [condition]
+:- func (pred) `===>` f0 = property.
+:- mode in((pred) is semidet) `===>` in = out is det.
+Left `===>` Right Left fails return [condition]
Left succeeds return apply(Right)
-:- func bool `===>` f0 = property.
-:- mode in `===>` in = out is det.
-Left `===>` Right Left == no return [condition]
+:- func bool `===>` f0 = property.
+:- mode in `===>` in = out is det.
+Left `===>` Right Left == no return [condition]
Left == yes return apply(Right)
:- func to_trivial(T, T, property) = property.
@@ -80,9 +90,10 @@
to_trivial(A, B, C) A == B return [trivial | C]
A != B return C
-:- func T `>>>` property = property.
-:- mode in `>>>` in = out is det.
-Left `>>>` Right return [ info(univ(Left)) | Right ]
+:- func T `>>>` property = property.
+:- mode in `>>>` in = out is det.
+Left `>>>` Right return [ info(univ(Left)) | Right ]
</pre></tr></table>
-
+</body>
+</html>
Index: T5.html
===================================================================
RCS file: /home/mercury1/repository/mercury/extras/quickcheck/tutes/T5.html,v
retrieving revision 1.2
diff -d -u -w -r1.2 T5.html
--- T5.html 3 Oct 2001 02:04:09 -0000 1.2
+++ T5.html 22 Feb 2002 03:52:12 -0000
@@ -1,39 +1,58 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
- <TITLE> QuickCheck </TITLE>
+<title>QuickCheck</title>
</head>
+<body>
+<p>
Files :
-<a href="use51.m">use51.m</a><BR>
+<a href="use51.m">use51.m</a>
+<br>
<a href="index.html">Back to main</a>
+
<H1> QuickCheck Tutorial 5 </H1>
-<h3> Generators - Basic </h3>
+<h2> Generators - Basic </h2>
-<pre>
+<p>
The invariant function is of the form
+<pre>
:- func Invariant_Function_X(T, T1, T2 ...) = property
:- mode Invariant_Function_X(in, in, in ...) = out.
+</pre>
Quickcheck generates random values for each input argument at run time.
The following types have default generators:
- - int
- - char
- - float
- - string
- - some functions (more detail in Tutorial 8)
- - any type defined as a discriminated union, provided
+<ul>
+ <li> int
+ <li> char
+ <li> float
+ <li> string
+ <li> some functions (more detail in Tutorial 8)
+ <li> any type defined as a discriminated union, provided
that all types in the body of the definition have
default/custom generators
- - any type defined as being equivalent to a type with a
+ <li> any type defined as being equivalent to a type with a
default/custom generator
+</ul>
+<p>
There is no code written to handle equivalent types. But it works
as if the compiler replaced all the equivalent types with their real type
before compiling.
+<p>
The default generator for int is rand_int/2, which has distribution:
-50% even distribution between [-100, 100]
-50% even distribution between [-2^31, 2^31]
-<P>
-<table border=0 width=100% bgcolor=#eeeee0><tr><td><pre>
+<table>
+<tr>
+<td> 50%
+<td> even distribution in the range [-100, 100]
+<tr>
+<td> 50%
+<td> even distribution in the range (-2^31, 2^31)
+ <br>(This will probably change to [int__min_int, int__max_int] in
+ a future version.)
+</table>
+
+<table border=0 width="100%" bgcolor="#eeeee0"><tr><td><pre>
:- func rand_int(rnd, rnd) = int.
:- mode rand_int(in, out) = out is det.
rand_int(BS0, BS) = Int :-
@@ -50,7 +69,7 @@
rand_allint(BS0, BS) = Int :-
next(1, Sign, BS0, BS1),
next(31, TempInt, BS1, BS),
- ( Sign > 0 ->
+ ( Sign > 0 ->
Int = TempInt
;
Int = -TempInt
@@ -58,8 +77,9 @@
</pre></tr></table>
Default for char is rand_char/2, with even spread over
char__to_int(Char, X) where X is (-1000, 1000).
-<P>
-<table border=0 width=100% bgcolor=#eeeee0><tr><td><pre>
+<!-- Maybe insert `∩ {I : some[C] char__to_int(C, I)}' or English comment. -->
+
+<table border=0 width="100%" bgcolor="#eeeee0"><tr><td><pre>
:- func rand_char(rnd, rnd) = char.
:- mode rand_char(in, out) = out is det.
rand_char(RS0, RS) = Char :-
@@ -78,14 +98,14 @@
cover all possible values, but may alter distribution.
If machine is more than 32bits, rand_float/2 will miss some values
but retains even distribution.
-<P>
-<table border=0 width=100% bgcolor=#eeeee0><tr><td><pre>
+
+<table border=0 width="100%" bgcolor="#eeeee0"><tr><td><pre>
:- func rand_float(rnd, rnd) = float.
:- mode rand_float(in, out) = out is det.
rand_float(BS0, BS) = Flt :-
next(31, Mant0, BS0, BS1),
next(1, Sign, BS1, BS2),
- ( Sign > 0 ->
+ ( Sign > 0 ->
Mant = Mant0
;
Mant = -Mant0
@@ -93,7 +113,7 @@
next(7, Exp, BS2, BS3),
next(1, ExpSign, BS3, BS),
Flt0 = float(Mant) * pow(2.0, Exp),
- ( ExpSign > 0, Flt0 \= 0.0 ->
+ ( ExpSign > 0, Flt0 \= 0.0 ->
Flt = 1.0/Flt0
;
Flt = Flt0
@@ -101,15 +121,23 @@
</pre></tr></table>
Default for string is rand_string/2, each element is generated by
rand_char/2.
-0.9^0 * 0.1 chance being string length == 0
-0.9^1 * 0.1 chance being string length == 1
-0.9^2 * 0.1 chance being string length == 2
-...etc...
-So the mean string length is Sum(0.1* 0.9^N * N) where N <- {0, infinity},
+<table summary="The probability of the string having length i is 0.9^i * 0.1.">
+<tr>
+ <td>0.9^0 * 0.1
+ <td>chance being string length == 0
+<tr>
+ <td>0.9^1 * 0.1
+ <td>chance being string length == 1
+<tr>
+ <td>0.9^2 * 0.1
+ <td>chance being string length == 2
+<tr>
+ <td>...etc...
+</table>
+So the mean string length is Sum(0.1* 0.9^N * N) where N ← {0, infinity},
which converges to 9.
-<P>
-<table border=0 width=100% bgcolor=#eeeee0><tr><td><pre>
+<table border=0 width="100%" bgcolor="#eeeee0"><tr><td><pre>
:- func rand_string(rnd, rnd) = string.
:- mode rand_string(in, out) = out is det.
rand_string(RS0, RS) = X :-
@@ -119,9 +147,11 @@
</pre></tr></table>
Note that the default generator for stirng actually uses the default generator
for discriminated union (indirectly).
+
+<p>
use51.m gives an illustration of generating int, char, float, string.
-<P>
-<table border=0 width=100% bgcolor=#eeeee0><tr><td><pre>
+
+<table border=0 width="100%" bgcolor="#eeeee0"><tr><td><pre>
:- module use51.
:- interface.
@@ -142,28 +172,28 @@
%---------------------------------------------------------------------------%
-main -->
+main -->
qcheck(qcheck__f(junk), "just to show the inputs", 5, [], []).
:- func junk(marks, char, float, string) = property.
junk(A, B, C, D) =
- {A,B,C,D} `>>>` [yes].
+ {A,B,C,D} `>>>` [yes].
</pre></tr></table>
There are a few thing to note about use51.m :
-<h4>
+<pre>
qcheck(qcheck__f(junk), "just to show the inputs", 5, [], []).
-</h4>
+</pre>
The 3rd argument is an int, which specifies how many times to run. In this
example 5 tests are run , but the default is 100. The other auguments will
be described later.
-<h4>
+<pre>
junk(A, B, C, D) =
- {A,B,C,D} `>>>` [yes].
-</h4>
+ {A,B,C,D} `>>>` [yes].
+</pre>
the invariant function doesn't do any testing, it always succeeds. But
-`>>>` collects all the inputs.
+`>>>` collects all the inputs.
A Sample output
-<h4>
+<pre>
Test Description : just to show the inputs
Number of test cases that succeeded : 5
Number of trivial tests : 0
@@ -172,10 +202,12 @@
1 {-50, '4', -3.55475907854864e+25, "\241r\371~~\316\002LJ~\204\246"}
1 {27, '\342', -311727734390784., "\377g.\001"}
1 {1389908257, '8', 2.63071847153664e+15, "\342"}
- 1 {-90973704, '<', -2.10559053720692e-22, ""}
+ 1 {-90973704, '<', -2.10559053720692e-22, ""}
1 {-896549770, 's', 7.72155851221736e+30, "[\230m\304\2561\254Q"}
-</h4>
+</pre>
The char and string output doesn't look pretty, since most are not printable,
eg: \342, \254
+</body>
+</html>
Index: T6.html
===================================================================
RCS file: /home/mercury1/repository/mercury/extras/quickcheck/tutes/T6.html,v
retrieving revision 1.2
diff -d -u -w -r1.2 T6.html
--- T6.html 3 Oct 2001 02:04:10 -0000 1.2
+++ T6.html 22 Feb 2002 03:52:12 -0000
@@ -1,27 +1,32 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
<html>
<head>
- <TITLE> QuickCheck </TITLE>
+<title>QuickCheck</title>
</head>
+<body>
+<p>
Files :
-<a href="use62.m">use62.m</a><BR>
+<a href="use62.m">use62.m</a>
+<br>
<a href="index.html">Back to main</a>
-<H1> QuickCheck Tutorial 6 </H1>
-<h3> Generators - Discriminated union & Specific Frequency</h3>
-<pre>
+
+<h1>QuickCheck Tutorial 6</h1>
+<h2>Generators: Discriminated Union & Specific Frequency</h2>
+
+<p>
Default generator is able to generate discriminated unions provided that all types
in the body of the definition have default/custom generators. In default frequency
mode, all branches at each level have the same chance of being selected.
-<P>
-<table border=0 width=100% bgcolor=#eeeee0><tr><td><pre>
+<table border=0 width="100%" bgcolor="#eeeee0"><tr><td><pre>
:- func rand_union(type_desc, list(frequency), list({type_desc,
list(frequency)}), list(user_gen_type), rnd, rnd) = univ.
:- mode rand_union(in,in,in,list_skel_in(user_gen_inst),in,out) = out is det.
</pre></tr></table>
use61.m shows the randomly generated value for the type bullet, with default
frequency :
-<P>
-<table border=0 width=100% bgcolor=#eeeee0><tr><td><pre>
+
+<table border=0 width="100%" bgcolor="#eeeee0"><tr><td><pre>
:- module use61.
:- interface.
@@ -43,23 +48,23 @@
%---------------------------------------------------------------------------%
:- type bullet
- ---> good(color)
+ ---> good(color)
; inaccurate(color)
; defective(color).
:- type color
- ---> black
+ ---> black
; white.
%---------------------------------------------------------------------------%
-main -->
+main -->
qcheck(qcheck__f(prop1), "even distribution", 1000, [], []).
:- func prop1(bullet) = property.
-prop1(X) = X `>>>` [yes].
+prop1(X) = X `>>>` [yes].
</pre></tr></table>
Sample output shows the expected distribution :
-<h4>
+<pre>
Test Description : even distribution
Number of test cases that succeeded : 1000
Number of trivial tests : 0
@@ -71,15 +76,19 @@
176 good(white)
178 defective(white)
178 good(black)
-</h4>
+</pre>
-<h3> Specific Frequency</h3>
-Specific Frequency changes a term's default frequency (which is evenly spread)
+
+<h2>Specific Frequency</h2>
+
+<p>Specific Frequency changes a term's default frequency (which is evenly spread)
to one the user has provided. General Frequency changes a type's default frequency
to one the user has provided. An example :
-<h4>
+<pre>
:- func Invariant_Function_X(bullet, bullet) = property.
-</h4>
+</pre>
+
+<p>
Different SF can be passed to the first and second bullet. For example, the first
bullet can have 80% chance of being black, while the second argument has 20% chance
of being black. However there can only be one GF for each type.
@@ -88,42 +97,53 @@
The draw back is that SF only goes as deep (down the branches) as the user
defines it, and the amount of work blows up as the depth of branches increases.
+<p>
Suppose there are two bullet manufacturers.
-Company_W 's bullet are painted black, and 50% good ones, 10% inaccurate, 40% defective.
-Company_B 's bullet are painted white, and 40% good ones, 30% inaccurate, 30% defective.
+Company_W's bullets are painted black; 50% are good, 10% inaccurate, 40% defective.
+Company_B's bullets are painted white; 40% are good, 30% inaccurate, 30% defective.
A good bullet always hits its target, inaccurate one misses 50% of time, defective bullet
always misses. And color does affect performance.
-<P>
-<table border=0 width=100% bgcolor=#eeeee0><tr><td><pre>
+<!-- XXX: The above is probably a typo; should probably say "colour itself doesn't affect performance". -->
+
+<table border=0 width="100%" bgcolor="#eeeee0"><tr><td><pre>
:- type frequency
- ---> {int, list(list(frequency))}.
+ ---> {int, list(list(frequency))}.
</pre></tr></table>
frequency defines the relative chance of a branch being selected, and gives information
of that branch's sub-branches.
list(frequency) contains distribution information about 1 discrimated union, ie: the list
must contain a frequency for each possible branch.
list(list(frequency)) contains distribution information about a list of discrimated unions.
-<P>
-<table border=1 width=100%><tr><td><pre>
+
+<p>
Let's try to describe Company_W's bullet, Bullet is discrimated union, so the list is 3 length long :
+<pre>
list(frequency)
+</pre>
There are 3 top level branches for Type Bullet, so the list is 3 length long :
+<pre>
[frequency_good, frequency_inaccurate, frequency_defective]
:- type frequency = {int, list(list(frequency))}.
frequency_good = {50, ...something_good...}
frequency_inaccurate = {10, ...something_inaccurate...}
frequency_defective = {40, ...something_defective...}
+</pre>
-Any int is a valid 1st argument of frequency, however negative numbers is viewed
-by qcheck as zeros.
+<p>
+Any int is a valid 1st argument of frequency. (Negative numbers are treated
+by qcheck as zeros.)
+<pre>
chance of good-bullet is 50 / (50 + 10 + 40)
the chance of inaccurate is 10 / (50 + 10 + 40)
the chance of defective is 40 / (50 + 10 + 40)
+</pre>
+<p>
Another example (for type bullet):
+<pre>
:- type frequency = {int, list(list(frequency))}.
frequency_good = {5, ...something_good...}
frequency_inaccurate = {1, ...something_inaccurate...}
@@ -132,41 +152,55 @@
the chance of good-bullet is 5 / (5 + 1 + 4)
the chance of inaccurate is 1 / (5 + 1 + 4)
the chance of defective is 4 / (5 + 1 + 4)
+</pre>
-In both example the result distribution is the same. ie (50% good,
+<p>
+In both examples, the result distribution is the same (i.e. 50% good,
10% inaccurate, 40% defective).
+<p>
...something_good... has format list(list(frequency)), and should describe the argument(s) of good/1.
good/1 only has 1 arguments, thus the list of 1 element,
+<pre>
[ info_color ]
+</pre>
+
+<p>
info_color has format list(frequency), color has 2 branches, thus this list is of 2 elements.
+<pre>
[ frequency_black, frequency_white ]
:- type frequency = {int, list(list(frequency))}.
frequency_black = {100, ...something_black...}
frequency_white = {0, ...something_white...}
+</pre>
+<p>
something_black has format list(list(frequency)), and should describe the argument(s) of black/0.
black/0 has no argument, thus the list is [], likewise for white/0.
If instead of black/0, it's black/3, eg:
-<h4>
+<pre>
:- type color
- ---> black(paint_manufacturer, warranty_type, warranty_provider)
+ ---> black(paint_manufacturer, warranty_type, warranty_provider)
; white(paint_manufacturer, warranty_type, warranty_provider)
-</h4>
+</pre>
Then you can either use [] to use default frequeny for generating paint_manufacturer, warranty_type,
and warranty_provider. Or you can specify a list of 3 element ; each element describing the frequency
of paint_manufacturer, warranty_type or warranty_provider.
+<pre>
So far: info_color = [ frequency_black, frequency_white ]
= [ {100, []}, {0, []} ]
Then: frequency_good = {50, ...something_good...}
= {50, [ info_color ] }
= {50, [ [ {100, []}, {0, []} ] ] }
+</pre>
+<p>
in this case ...something_good..., ...something_inaccurate... and ...something_defective are the same,
since they all describe a list which contains Color that has the same distribution.
+<pre>
So: frequency_good = {50, [ [ {100, []}, {0, []} ] ] }
frequency_inaccurate = {10, [ [ {100, []}, {0, []} ] ] }
frequency_defective = {40, [ [ {100, []}, {0, []} ] ] }
@@ -176,17 +210,22 @@
{10, [ [ {100, []}, {0, []} ] ] },
{40, [ [ {100, []}, {0, []} ] ] }
]
+</pre>
-For Company_W 's bullet , it's list(frequency) would be :
+<p>
+For Company_W's bullet, its list(frequency) would be :
+<pre>
[frequency_good, frequency_inaccurate, frequency_defective]
= [ {40, [ [ {0, []}, {100, []} ] ] },
{30, [ [ {0, []}, {100, []} ] ] },
{30, [ [ {0, []}, {100, []} ] ] }
]
-</pre></tr></table>
+</pre>
+
+<p>
The complete code (use62.m) :
-<P>
-<table border=0 width=100% bgcolor=#eeeee0><tr><td><pre>
+
+<table border=0 width="100%" bgcolor="#eeeee0"><tr><td><pre>
:- module use62.
:- interface.
@@ -208,17 +247,17 @@
%---------------------------------------------------------------------------%
:- type bullet
- ---> good(color)
+ ---> good(color)
; inaccurate(color)
; defective(color).
:- type color
- ---> black
+ ---> black
; white.
%---------------------------------------------------------------------------%
-main -->
+main -->
{ freq_B(B) },
{ freq_W(W) },
qcheck(qcheck__f(prop2), "bullet fight", 10000, [[],B,W], []).
@@ -240,9 +279,9 @@
].
:- func prop2(int, bullet, bullet) = property.
-prop2(Seed, B, W) = fight(Seed, B, W) `>>>`
- ({"ComB",B} `>>>`
- ({"ComW", W} `>>>` [yes])
+prop2(Seed, B, W) = fight(Seed, B, W) `>>>`
+ ({"ComB",B} `>>>`
+ ({"ComW", W} `>>>` [yes])
).
:- func fight(int, bullet, bullet) = string.
@@ -254,7 +293,7 @@
(if B_hit = W_hit
then
String = "draw"
- else if B_hit > W_hit
+ else if B_hit > W_hit
then
String = "B win"
else
@@ -282,17 +321,18 @@
).
</pre></tr></table>
In use62.m
-<h4>
-main -->
+<pre>
+main -->
{ freq_B(B) },
{ freq_W(W) },
qcheck(qcheck__f(prop2), "bullet fight", 10000, [[],B,W], []).
-</h4>
+</pre>
The 4th argument of qcheck/7 is for passing Specific Frequency. Because the
invariant function has three input arguments, qcheck/7 's 4th argument must
be list of 3.
[[],B,W]
+<p>
The first argument of prop2/3 is of type int, and I've passed [] as
it's SF. When qcheck is trying to generate that int, it will completely
ignore the [] since an int is not a discriminated union. In that sense,
@@ -301,8 +341,9 @@
recognize that [] is for the first argument, B is for the second argument and
W is for the third argument.
+<p>
A sample output:
-<h4>
+<pre>
Test Description : bullet fight
Number of test cases that succeeded : 10000
Number of trivial tests : 0
@@ -317,9 +358,9 @@
4039 {"ComW", good(white)}
5064 "draw"
5074 {"ComB", good(black)}
-</h4>
+</pre>
Regroup the output to make comparison :
-
+<pre>
5074 {"ComB", good(black)
909 {"ComB", inaccurate(black)}
4017 {"ComB", defective(black)}
@@ -327,37 +368,45 @@
4039 {"ComW", good(white)}
3012 {"ComW", inaccurate(white)}
2949 {"ComW", defective(white)}
+</pre>
+<p>
Note that ComB only makes black bullet; ComW only white. And their bullet quality is
what was expected of them.
+<pre>
2403 "B win"
2533 "W win"
5064 "draw"
+</pre>
-
+<p>
Walk through in generating a Company_B 's bullet :
- 1 The program first enters the generator with
+<ol>
+ <li> The program first enters the generator with
+<pre>
SF = [ {50, [ [ {100, []}, {0, []} ] ] },
{10, [ [ {100, []}, {0, []} ] ] },
{40, [ [ {100, []}, {0, []} ] ] }
].
+</pre>
- 2 Suppose the 3rd branch is selected, then qcheck will extract
- [ {100, []}, {0, []} ] from {40, [ [ {100, []}, {0, []} ] ] }
+ <li>Suppose the 3rd branch is selected, then qcheck will extract
+ <tt>[ {100, []}, {0, []} ]</tt> from <tt>{40, [ [ {100, []}, {0, []} ] ] }</tt>.
- 3 It then calls the generator with SF = [ {100, []}, {0, []} ]
+ <li> It then calls the generator with SF = [ {100, []}, {0, []} ]
- 4 So qcheck enters generator for the sub-branch (for color) with
+ <li> So qcheck enters generator for the sub-branch (for color) with
SF = [ {100, []}, {0, []} ]
- 5 Suppose the 1st branch is selected, then qcheck will extract []
+ <li> Suppose the 1st branch is selected, then qcheck will extract []
from {100, []}
- 6 Since constructor black/0 has no argument, the program will stop
+ <li> Since constructor black/0 has no argument, the program will stop
the recursive call.
+</ol>
-
-
+</body>
+</html>
Index: T7.html
===================================================================
RCS file: /home/mercury1/repository/mercury/extras/quickcheck/tutes/T7.html,v
retrieving revision 1.2
diff -d -u -w -r1.2 T7.html
--- T7.html 3 Oct 2001 02:04:10 -0000 1.2
+++ T7.html 22 Feb 2002 03:52:13 -0000
@@ -1,25 +1,35 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
<html>
<head>
- <TITLE> QuickCheck </TITLE>
+<title>QuickCheck</title>
</head>
+<body>
+<p>
Files :
-<a href="use71.m">use71.m</a><BR>
+<a href="use71.m">use71.m</a>
+<br>
<a href="index.html">Back to main</a>
-<H1> QuickCheck Tutorial 7 </H1>
-<h3> Generators - General Frequency</h3>
-<pre>
+<h1>QuickCheck Tutorial 7</h1>
+
+<h2>Generators - General Frequency</h2>
+
+<p>
General Frequency follows the ideas in Specific Frequency. You must understand
the format of Specific Frequency in order to write General Frequency. However
the amount of work in GF is usually less then in SP. In GF, the user should
specify one level down in branches, where a practicl SP may be 3+ level down.
+<p>
Back in Tutorial 3, an invariant function was written to test the law :
+<pre>
reverse (reverse xs) = xs
-<h4>
+</pre>
+
+<pre>
:- func testing4(list(float)) = property.
testing4(Xs) =
- list_length(Xs) `>>>` (nrev(nrev(Xs)) `===` Xs).
+ list_length(Xs) `>>>` (nrev(nrev(Xs)) `===` Xs).
Test Description : testing4
Number of test cases that succeeded : 100
@@ -34,62 +44,78 @@
16 2
18 1
53 0
-</h4>
-The display of testing4 shows that 53 cases of lenggh == 0
+</pre>
+The display of testing4 shows that
+<pre>
+ 53 cases of length == 0
18 cases of length == 1
16 cases of length == 2
...etc...
-The length of of the list is heavily biased towards the short end. In the limit with
+</pre>
+The length of the list is heavily biased towards the short end. In the limit with
even distribution along the branches, the list will have :
+<pre>
50% length == 0
25% length == 1
12.5% length == 2
6.25% length == 3
3.125% length == 4
-...etc... halfing the probability in eash step.
-<h4>
+</pre>
+...etc... halving the probability in each step.
+<pre>
:- type list(T)
- ---> []
+ ---> []
; [T | list(T)].
-</h4>
+</pre>
At any given length accumulated so far, there is a 50-50 chance of either
stopping there (if the first branch is chosen) or going on to a longer
list (if the second branch is chosen).
+<p>
The 5th argument of qcheck/7 takes General Frequency, it's of type
- list({type_desc, list(frequency)})
-each element of the list contains the General Frequency for a type.
+<code>list({type_desc, list(frequency)})</code>.
+Each element of the list contains the General Frequency for a type.
The list length can be increased if the 2nd branch if favoured over the 1st branch.
-<h4>
-From Tute6 :
+
+<p>From Tute6:
frequency defines the relative chance of a branch being selected, plus information about that
branch's sub-branches.
-list(frequency) contains distribution information about 1 discriminated union, ie: the list
+list(frequency) contains distribution information about 1 discriminated union, i.e. the list
should contain frequencies for all possible branches.
list(list(frequency)) contains distribution information about a list of discriminated unions.
-</h4>
+
+<p>
A list is a discriminated union. To describe it, the correct format will be list(frequency),
which matches the 2nd term of list({type_desc, list(frequency)})
+
<P>
-<table border=1 width=100%><tr><td><pre>
The list(frequency) for list(T) should have two elements, since the definition of list/1 has
two branches.
+<pre>
Output = [ frequency_a, frequency_b ]
frequency_a = { 10, ...something_a... }
frequency_b = { 90, ...something_b... }
-That is 10% take 1st branch, 90% take the 2nd branch.
+</pre>
+I.e. 10% take the 1st branch, 90% take the 2nd branch.
+<p>
The constrctor []/0 takes no argument, thus something_a is [], ie:
frequency_a = { 10, [] }
+<p>
+<!-- Should the below become `[|](...)'? -->
The 2nd branch constructor .(T, list(T)) takes 2 arguments. In specific frequency that would
mean a list of two elements (or choose defalut []) :
+<pre>
something_b = list(list(frequency)) = [ A, B ]
+</pre>
In General Frequency the user can specify down more than 1 level, however it is not required
in this case. Define something_b = { 90, [] }.
+<p>
Put it all together:
+<pre>
list(frequency)
= [ frequency_a, frequency_b ]
= [ { 10, [] } , { 90, [] } ]
@@ -97,14 +123,16 @@
Then
{ type_desc, list(frequency) }
= { type_of([0.0]), [ { 10, [] } , { 90, [] } ] }
+</pre>
+<p>
Now for type list(float), there is 10% chance of selecting 1st branch, and 90% chance of selecting
2nd branch at EVERY level.
-</pre></tr></table>
+<p>
The complete code (use71.m) :
-<P>
-<table border=0 width=100% bgcolor=#eeeee0><tr><td><pre>
+
+<table border=0 width="100%" bgcolor="#eeeee0"><tr><td><pre>
:- module use71.
:- interface.
@@ -123,7 +151,7 @@
%---------------------------------------------------------------------------%
-main -->
+main -->
{ freq_list(F) },
qcheck(qcheck__f(testing4), "testing4", 1000, [], [F]).
@@ -134,10 +162,10 @@
:- func testing4(list(float)) = property.
testing4(Xs) =
- list_length(Xs) `>>>` (nrev(nrev(Xs)) `===` Xs).
+ list_length(Xs) `>>>` (nrev(nrev(Xs)) `===` Xs).
</pre></tr></table>
A sample output shows the lists are much longer :
-<h4>
+<pre>
Test Description : testing4
Number of test cases that succeeded : 1000
Number of trivial tests : 0
@@ -191,34 +219,41 @@
72 2
91 1
95 0
-</h4>
+</pre>
+<p>
Summary on default frequency, specific frequency, general frequency :
-1 Before Quickcheck generates a term, it considesr the term's type.
+<ol>
+ <li><p>Before Quickcheck generates a term, it considers the term's type.
If it's not a discriminated union, all the frequency input is ignored
and lost forever.
-2 If it is a discriminated union, then Quickcheck generates the term
+ <li><p>If it is a discriminated union, then Quickcheck generates the term
according to the specific frequency. In cases where the specific
frequency is [], then Quickcheck will search the general frequency
list to find the matching type.
-3 If no matching type is found, then generate the term (at this level) evenly
+ <li><p>If no matching type is found, then generate the term (at this level) evenly
+<pre>
eg: :- type coin
- ---> small(face)
+ ---> small(face)
; large(color).
:- type face
- ---> head
+ ---> head
; tail.
+</pre>
The chance between small/large is even, but that doesn't mean chance
between face:head/tail is even.
-4 If matching type is found, then Quickcheck copies that frequency information,
+
+ <li><p>If matching type is found, then Quickcheck copies that frequency information,
and treats that as the specific frequency.
+</ol>
+<p>
In the list(float) example:
-<h4>
+<pre>
qcheck(qcheck__f(testing4), "testing4", 1000, [], [F])
F = { type_of([0.0]), [ { 10, [] } , { 90, [] } ] }
-</h4>
+</pre>
Quickcheck will first find [] as specific frequency (since [] is passed to qcheck),
so it will look in the general frequency list for the information on how to generate
list(float). That information will be extracted. The function which generates
@@ -229,6 +264,7 @@
as specific frequency, then it will find general frequency list contains information on
how to generate list(float). That information will be copied over...etc...
That is:
+<pre>
0 enter generator
1 SF = [],
2 search GF, found, [ { 10, [] } , { 90, [] } ]
@@ -240,19 +276,10 @@
6 generate the sub-branch with SF = []
7 enter generator (for the sub-branch), SF = [], go back to step 1
+</pre>
+<p>
The actual code does not restart the generator.
-
-
-
-
-
-
-
-
-
-
-
-
-
+</body>
+</html>
Index: T8.html
===================================================================
RCS file: /home/mercury1/repository/mercury/extras/quickcheck/tutes/T8.html,v
retrieving revision 1.2
diff -d -u -w -r1.2 T8.html
--- T8.html 3 Oct 2001 02:04:10 -0000 1.2
+++ T8.html 22 Feb 2002 03:52:13 -0000
@@ -1,25 +1,34 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2//EN">
<html>
<head>
- <TITLE> QuickCheck </TITLE>
+<title>QuickCheck</title>
</head>
+<body>
+<p>
Files :
-<a href="use81.m">use81.m</a><BR>
+<a href="use81.m">use81.m</a>
+<br>
<a href="index.html">Back to main</a>
-<H1> QuickCheck Tutorial 8 </H1>
-<h3> Generators - Random Functions</h3>
-<pre>
+<h1>QuickCheck Tutorial 8</h1>
+
+<h2>Generators - Random Functions</h2>
+
+<p>
Currently Quickcheck only has default generators for random functions that
have 0 to 10 inputs, 1 output, and is in forward mode. This generated function
can run on any type of inputs, but the output must be a type for which there is
a custom/default generator.
+
+<p>
The output may be indepedent of zero or more of the input arguments.
By this we mean that the value of an input argument may have no bearing upon the
calculation of the output. There is a 5% chance per argument of this occurring.
+<p>
An example (use81.m)
-<P>
-<table border=0 width=100% bgcolor=#eeeee0><tr><td><pre>
+
+<table border=0 width="100%" bgcolor="#eeeee0"><tr><td><pre>
:- module use81.
:- interface.
@@ -37,9 +46,9 @@
:- import_module qcheck, rnd.
:- type strange(T1, T2)
- ---> wierd(T1, T2, T1).
+ ---> wierd(T1, T2, T1).
-main -->
+main -->
qcheck(qcheck__f(prop1), "prop1", 1000, [], []),
qcheck(qcheck__f(prop2), "prop2", 1000, [], []),
qcheck(qcheck__f(prop3), "prop3", 1000, [], []),
@@ -78,8 +87,9 @@
).
</pre></tr></table>
+<p>
A sample output:
-<h4>
+<pre>
Test Description : prop1
Number of test cases that succeeded : 1000
Number of trivial tests : 0
@@ -109,38 +119,32 @@
Distributions of selected argument(s) :
1 "equal"
999 "not equal"
-</h4>
+</pre>
+<p>
prop1/1 just shows that given the same input, the output of the
sample function is the same.
+<p>
prop3/1 shows that given different input, the random function will
usually give different output (940/1000 cases). For the rest 60/1000
cases, either the output is independent of input (most likely). Or
it just so happens the output is the same for FFF(0) and FFF(1).
-(Noet 60/1000 is roughly 5%)
+(Note 60/1000 is roughly 5%)
+<p>
prop2/1 shows 256/1000 cases shows that the random function returned the
same output for different inputs. The real differenct between prop3/1 and
prop2/1 is that the output of prop2/1 is list(int), which means the chance
of generating [] is high (50% chance), and that's where 256/1000 cases come
from.
+<p>
prop4/1 's random function takes two inputs, the chance of both inputs being
independent of output is less compare to a random function which only takes
-1 input. eg FFF(in) = out, out independent of in is 5% chance
+1 input. e.g.:<br>
+ FFF(in) = out, out independent of in is 5% chance<br>
FFF(in, in) = out, out independent of in is 5% * 5% chance
-
-
-
-
-
-
-
-
-
-
-
-
-
+</body>
+</html>
Index: T9.html
===================================================================
RCS file: /home/mercury1/repository/mercury/extras/quickcheck/tutes/T9.html,v
retrieving revision 1.2
diff -d -u -w -r1.2 T9.html
--- T9.html 3 Oct 2001 02:04:10 -0000 1.2
+++ T9.html 22 Feb 2002 03:52:13 -0000
@@ -1,24 +1,30 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
- <TITLE> QuickCheck </TITLE>
+<title>QuickCheck</title>
</head>
+<body>
Files :
-<a href="use91.m">use91.m</a><BR>
+<a href="use91.m">use91.m</a>
+<br>
<a href="index.html">Back to main</a>
-<H1> QuickCheck Tutorial 9 </H1>
-<h3> User Defined generators</h3>
-<pre>
-The default generator will be called only if a user defined generator does not.
+<h1>QuickCheck Tutorial 9</h1>
+
+<h2>User Defined generators</h2>
+
+<p>
+The default generator will be called only if a user-defined generator does not.
+<!-- XXX: Should the above be "does not exist"? -->
The user definded generator must conform to the following format:
-<P>
-<table border=0 width=100% bgcolor=#eeeee0><tr><td><pre>
+
+<table border=0 width="100%" bgcolor="#eeeee0"><tr><td><pre>
:- func gen_f(type_desc, list(frequency), list({type_desc, list(frequency)}),
list(user_gen_type), rnd, rnd) = univ.
:- mode gen_f(in, in, in, list_skel_in(user_gen_inst), in, out) = out is det.
:- type user_gen_type
- ---> { type_desc,
+ ---> { type_desc,
func(type_desc, list(frequency),
list({type_desc, list(frequency)}),
list(user_gen_type), rnd, rnd) = univ
@@ -31,15 +37,15 @@
list_skel_in(user_gen_inst), in, out) = out is det
}).
</pre></tr></table>
-The last two arguments of type rnd, are the random supply, in & out.
-(Ignore the rest of arguments) use91.m shows a user defined generator for type :
-<h4>
+The last two arguments of type rnd, are the random supply, in & out.
+(Ignore the rest of arguments.)
+use91.m shows a user defined generator for type:
+<pre>
func fff(int) = int
mode fff(in) = out
+</pre>
-</h4>
-<P>
-<table border=0 width=100% bgcolor=#eeeee0><tr><td><pre>
+<table border=0 width="100%" bgcolor="#eeeee0"><tr><td><pre>
:- module use91.
:- interface.
@@ -56,7 +62,7 @@
:- import_module int, list, std_util.
:- import_module qcheck, rnd.
-main -->
+main -->
qcheck(qcheck__f(prop1), "user function", 100, [], [],
[{type_of(some_function), gen_f}]),
qcheck(qcheck__f(prop1), "no user function", 100, [], [], []).
@@ -75,8 +81,10 @@
:- func prop1(func(int)=int) = property.
:- mode prop1(in(func(in)=out is det)) = out is det.
prop1(FFF) = FFF(8) `===` (8 * 2).
+</pre></tr></table>
-Sample output:
+<p>Sample output:
+<pre>
Test Description : user function
Number of test cases that succeeded : 100
Number of trivial tests : 0
@@ -86,69 +94,99 @@
Test description : no user function
Falsifiable :
'<<predicate>>'
-</pre></tr></table>
+</pre>
-The user defined generator is gen_f/6, which ignores the first 4 arguments, and
+<p>The user defined generator is gen_f/6, which ignores the first 4 arguments, and
assigns rnd output equal to the input since gen_f doesn't use it.
-(all that was trivial, basiclly gen_f/6 ignores all of the inputs) And it returns
+(All that was trivial, basically gen_f/6 ignores all of the inputs.)
+And it returns
some_function/1 in a univ.
-<h4>
+<pre>
:- pred qcheck(T, string, int, list(list(frequency)),
list({type_desc, list(frequency)}),
- list(user_gen_type), io__state, io__state) <= testable(T).
+ list(user_gen_type), io__state, io__state) <= testable(T).
:- mode qcheck(in, in, in, in, in, list_skel_in(user_gen_inst), di, uo) is det.
qcheck(qcheck__f(prop1), "user function", 100, [], [],
[{type_of(some_function), gen_f}]),
-</h4>
+</pre>
qcheck/8 is used in use91.m. The last argument takes in the user-defined
-generators. The format is list(user_gen_type), since there is only 1 user
-defined generator, the list contains 1 element : {type_of(some_function), gen_f}.
- type_of(some_function) : describes what type gen_f generates
- gen_f : is the actual generator
+generators. The format is <code>list(user_gen_type)</code>, since there is only 1 user
+defined generator, the list contains 1 element : <code>{type_of(some_function), gen_f}</code>.
-the invariant function is true only if FFF(8) `===` (8 * 2). The 2nd test shows a random
-function will 'never' do that, but the 1st test with user defined generator will always
+<table>
+<tr>
+ <td>type_of(some_function)</td>
+ <td>describes what type gen_f generates</td>
+</tr>
+<tr>
+ <td>gen_f</td>
+ <td>is the actual generator</td>
+</tr>
+</table>
+
+<p>The invariant function is true only if <code>FFF(8) `===` (8 * 2)</code>.
+The 2nd test shows a random
+function will "never" do that, but the 1st test with user defined generator will always
generate the functions Y = 2 * X
-<h4>
+<pre>
:- func gen_f(type_desc, list(frequency), list({type_desc, list(frequency)}),
list(user_gen_type), rnd, rnd) = univ.
:- mode gen_f(in, in, in, list_skel_in(user_gen_inst), in, out) = out is det.
-</h4>
+</pre>
-1st input of type type_desc is the type_of of the current term the generator
- is required to generate. It could be useful if the
+<table>
+<thead>
+<tr>
+<th>Argument<br>number</th>
+<th>Type</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>1</td>
+<td>type_desc</td>
+<td>The <code>type_of</code> of the current term that the generator
+is required to generate. It can be useful if the
generator is able to generate more than one type,
- thus the type_desc can be used to determine wihch
- one.
-
-2st input of type list(frequency) is the specific frequency for this term, meaningless
+thus the <code>type_desc</code> can be used to determine which
+one.</td>
+</tr>
+<tr>
+<td>2</td>
+<td>list(frequency)</td>
+<td>Specific frequency for this term; meaningless
if the term is not a discriminated union. The user
can choose to ignore the setting even if the term is
- a discriminated union.
-
-3rd input of type list({type_desc, list(frequency)}) is a list of general frequency
-
-4th input of type list(user_gen_type) is a list of user defined generators
-
-5th input of type rnd random number supply
-
-6th input of type rnd random number return, let return = supply if not used.
-
-Look at rand_union/6 to find out how to write code which extracts/analyses specific frequency
-and eneral frequency.
-Look at gen/7 to find out how to wrote code which extract/analysis user defined generators.
-
-
-
-
-
-
-
-
-
-
-
-
+a discriminated union.</td>
+</tr>
+<tr>
+<td>3</td>
+<td>list({type_desc, list(frequency)})</td>
+<td>List of general frequency.</td>
+</tr>
+<tr>
+<td>4</td>
+<td>list(user_gen_type)</td>
+<td>List of user-defined generators.</td>
+</tr>
+<tr>
+<td>5</td>
+<td>rnd</td>
+<td>Random number supply.</td>
+</tr>
+<tr>
+<td>6</td>
+<td>rnd</td>
+<td>Random number return. Let return = supply if not used.</td>
+</tr>
+</table>
+<p>Look at <code>rand_union/6</code> to find out how to write code that
+extracts/analyses specific frequency and general frequency.
+Look at <code>gen/7</code> to find out how to write code that
+extracts/analyses user-defined generators.
+</body>
+</html>
Index: index.html
===================================================================
RCS file: /home/mercury1/repository/mercury/extras/quickcheck/tutes/index.html,v
retrieving revision 1.3
diff -d -u -w -r1.3 index.html
--- index.html 3 Oct 2001 02:13:15 -0000 1.3
+++ index.html 22 Feb 2002 03:52:13 -0000
@@ -1,26 +1,27 @@
+<!DOCTYPE html PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html>
<head>
- <TITLE> QuickCheck </TITLE>
+<title>QuickCheck</title>
</head>
+<body>
-<H1> Quickcheck for Mercury</H1>
-
-<H3> HTML Version </H3>
+<h1>Quickcheck for Mercury</h1>
<ol>
-<li> <a href="T1.html">Intro & `===`</a>
-<li> <a href="T2.html">Conditional laws & `===>`</a>
-<li> <a href="T3.html">Monitoring Data, to_trivial/3, `>>>`</a>
-<li> <a href="T4.html">Summary - Invariant Function & Property</a>
+<li> <a href="T1.html">Intro & <code>`===`</code></a>
+<li> <a href="T2.html">Conditional laws & <code>`===>`</code></a>
+<li> <a href="T3.html">Monitoring Data, <code>to_trivial</code>/3, <code>`>>>`</code></a>
+<li> <a href="T4.html">Summary - Invariant Function & Property</a>
<li> <a href="T5.html">Generators basic</a>
-<li> <a href="T6.html">Discriminated union & Specific Frequency</a>
+<li> <a href="T6.html">Discriminated union & Specific Frequency</a>
<li> <a href="T7.html">General Frequency</a>
<li> <a href="T8.html">Random Functions</a>
<li> <a href="T9.html">User Defined Generators</a>
-<li> <a href="T10.html">Summary - Generators</pre></a>
+<li> <a href="T10.html">Summary - Generators</a>
</ol>
+<p>
Feedback? Mail <a href="mailto:xcsm at students.cs.mu.oz.au">Simon</a>.
-</BODY>
+</body>
</html>
--------------------------------------------------------------------------
mercury-reviews mailing list
post: mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------
More information about the reviews
mailing list