Files
mercury/extras/quickcheck/tutes/T2.html
David Overton 07038626c1 The following change was made by Peter Moulder <pmoulder@csse.monash.edu.au>.
Estimated hours taken: 2

The following change was made by Peter Moulder <pmoulder@csse.monash.edu.au>.

extras/quickcheck/tutes/*.html:

	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.
2002-02-24 23:28:49 +00:00

179 lines
5.5 KiB
HTML

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>QuickCheck</title>
</head>
<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="index.html">Back to main</a>
<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
<pre>
X =&lt; Y =&gt; max x y == y
</pre>
can be represented by the definition :
<pre>
:- func law(int, int) = property.
law(X, Y) = (X =&lt; Y) `===&gt;` (mymax(X, Y) `===` Y).
</pre>
or alternatively can be represented as :
<pre>
:- func law2(int, int) = property.
law2(X, Y) = is_less_equal(X, Y) `===&gt;` (mymax(X, Y) `===` Y).
:- func is_less_equal(int, int) = bool.
is_less_equal(X, Y) = Bool :-
(if X =&lt; Y
then
Bool = yes
else
Bool = no
).
</pre>
The difference between law1 and law2 is the left argument of `===&gt;`.
<samp>(X =&lt; Y)</samp> is of type (pred) whereas
<samp>is_less_equal(X, Y)</samp> evaluates to type bool.
`===&gt;` is overloaded to take both types.
<p>
The complete use20.m:
<table border=0 width="100%" bgcolor="#eeeee0" summary="use20.m source code"><tr><td><pre>
:- module use20.
:- interface.
:- use_module io.
:- pred main(io__state, io__state).
:- mode main(di, uo) is det.
%---------------------------------------------------------------------------%
:- implementation.
:- import_module int, list, bool.
:- import_module qcheck, mymax.
%---------------------------------------------------------------------------%
main --&gt;
qcheck(qcheck__f(law), "testing mymax using `===&gt;` for (pred)"),
qcheck(qcheck__f(law2), "testing mymax using `===&gt;` for bool").
:- func law(int, int) = property.
law(X, Y) = (X =&lt; Y) `===&gt;` (mymax(X, Y) `===` Y).
:- func law2(int, int) = property.
law2(X, Y) = is_less_equal(X, Y) `===&gt;`
(mymax(X, Y) `===` Y).
:- func is_less_equal(int, int) = bool.
is_less_equal(X, Y) = Bool :-
(if X =&lt; Y
then
Bool = yes
else
Bool = no
).
</pre></tr></table>
After running the program, test statistics will be something like:
<pre>
Test Description : testing mymax using `===&gt;` 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 `===&gt;` 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) :
</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) :
<pre>
:- func law(int, int) = property.
law(X, Y) = notzero(Y) `===&gt;` ((X =&lt; Y) `===&gt;` (mymax(X, Y) `===` Y)).
:- pred notzero(int).
:- mode notzero(in) is semidet.
notzero(X) :- X \= 0.
</pre>
<p>
The right argument of `===&gt;` 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.
:- use_module io.
:- pred main(io__state, io__state).
:- mode main(di, uo) is det.
%---------------------------------------------------------------------------%
:- implementation.
:- import_module int, bool.
:- import_module qcheck.
%---------------------------------------------------------------------------%
main --&gt;
qcheck(qcheck__f(law1), "passing property"),
qcheck(qcheck__f(law2), "passing (func) = property").
:- func law1(int, int) = property.
law1(X, Y) = notzero(Y) `===&gt;` qcheck__f( (func) = ((X // Y) `===` (X // Y)) ).
:- func law2(int, int) = property.
law2(X, Y) = notzero(Y) `===&gt;` ( (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 `===&gt;`.
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 `===&gt;`'s left argument is 'bool:no' or
'(pred):failure'.
<p>The implication combinator `===&gt;` 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
`===&gt;` will just return 'property:[condition]'.
If the property list contains one or more 'condition', the test result is
ignored.
</body>
</html>