[m-dev.] for review: quickcheck user guide

Mark Anthony BROWN dougl at cs.mu.OZ.AU
Mon Feb 12 18:26:47 AEDT 2001


Hi,

Here is the first part of my review.  I've addressed some issues with
grammar/typos/etc., but there are some other structural issues I haven't
mentioned.  I'll post more of the review soon.

Cheers,
Mark.

Xiao Chun Simon MEI writes:
> Estimated hours taken:	40	
> 
> A collection of wed pages written as a user guide for quickcheck.

s/wed/web/

> It covers the syntax and features supported by current version of quickcheck.
> Below are the source code of those web pages. It's probably best viewed by
> a web browser at www.cs.mu.oz.au/~xcsm

The last two sentences don't belong in the log message.  Log messages
are useful because we can look back at them and understand why a change
in the past was made.  If in future we look back at this log message the
URL will be a dangling reference, since you are unlikely to leave those
pages there permanently.

(Note that it was useful to reviewers that you provided the URL, but not
in the log message.)

> 
> 
> quickcheck/tutes/T1.html:
> 	New file, covers the 1st topic 
> quickcheck/tutes/T2.html:
> 	New file, covers the 2nd topic 
> quickcheck/tutes/T3.html:
> 	New file, covers the 3rd topic 
> quickcheck/tutes/T4.html:
> 	New file, covers the 4th topic 
> quickcheck/tutes/T5.html:
> 	New file, covers the 5th topic 
> quickcheck/tutes/T6.html:
> 	New file, covers the 6th topic 
> quickcheck/tutes/T7.html:
> 	New file, covers the 7th topic 
> quickcheck/tutes/T8.html:
> 	New file, covers the 8th topic 
> quickcheck/tutes/T9.html:
> 	New file, covers the 9th topic 
> quickcheck/tutes/index.html:
> 	New file, index page 
> quickcheck/tutes/mymax.m:
> 	New file, contain sample function mymax 
> quickcheck/tutes/numbers.html:
> 	New file, sub-page for T6.html 
> quickcheck/tutes/testrev.m:
> 	New file, contains sample function testrev 
> quickcheck/tutes/testrev2.m:
> 	New file, contains sample predicate testrev2
> quickcheck/tutes/use.m:
> 	New file, contains example for T1.html
> quickcheck/tutes/use1.m:
> 	New file, contains example for T1.html
> quickcheck/tutes/use11.m:
> 	New file, contains example for T1.html
> quickcheck/tutes/use2.m:
> 	New file, contains example for T2.html
> quickcheck/tutes/use20.m:
> 	New file, contains example for T2.html
> quickcheck/tutes/use21.m:
> 	New file, contains example for T3.html
> quickcheck/tutes/use31.m:
> 	New file, contains example for T3.html
> quickcheck/tutes/use33.m:
> 	New file, contains example for T4.html
> quickcheck/tutes/use51.m:
> 	New file, contains example for T5.html
> quickcheck/tutes/use62.m:
> 	New file, contains example for T6.html
> quickcheck/tutes/use71.m:
> 	New file, contains example for T7.html
> quickcheck/tutes/use81.m:
> 	New file, contains example for T8.html
> quickcheck/tutes/use91.m:
> 	New file, contains example for T9.html
> 

Please group these together in a logical way, so that they are easier to
read.  For example:

	quickcheck/tutes/T*.html:
		New files, covering each of the tutorial topics.

etc.

> 
> 
> Index: quickcheck/tutes/T1.html
> ===================================================================
> RCS file: T1.html
> diff -N T1.html
> --- /dev/null	Wed Nov 15 09:24:47 2000
> +++ T1.html	Mon Feb  5 16:01:52 2001
> @@ -0,0 +1,224 @@
> +<html>
> +<head> 
> +	<TITLE> QuickCheck </TITLE>
> +</head>
> +Files : 
> +<a href="use.m">use.m</a>
> +<a href="use1.m">use1.m</a>
> +<a href="use11.m">use11.m</a>
> +<a href="testrev.m">testrev.m</a>
> +<a href="testrev2.m">testrev2.m</a><BR>
> +<a href="index.html">Back to main</a>
> +
> +<H1> QuickCheck Tutorial 1 </H1>
> +
> +
> +<pre>
> +In order to test the validity of a predicate/function via quickcheck, 
> +the user needs the following components :

Since this is a tutorial, "the user" is the person reading this.  So I
think it would be more appropriate to refer to them as "you".  That is:

	In order to test the validity of a predicate/function via
	quickcheck, you need ...



> +	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
> +
> +A Simple Example 
> +Let XXX.m be "testrev.m", which contains testrev/1 :
> +<P>
> +<table border=0 width=100% bgcolor=#eeeee0><tr><td><pre>
> +	:- func testrev(list(T)) = list(T).
> +	:- mode testrev(in) = out is det.
> +	testrev([]) = [].
> +	testrev([X|Xs]) = Ys :- 
> +		list__append(testrev(Xs), [X], Ys).
> +</pre></tr></table>
> +testrev/1 is the Mercury equivalent of Haskell's reverse function. We 
> +want to test whether testrev/1 is properly implemented.

This function is widely used in examples of declarative programming, so
I wouldn't refer to it as Haskell's reverse.  It is generally called
"naive reverse" (or nrev/1), because of the simple implementation.  I would
change testrev to nrev in this example.

> +
> +Let YYY.m be "use.m". It must contain a main/2, and an 
> +invariant function. If testrev/1 is correctly implemented then it 
> +should satisfy the following rules:
> +<H4>
> +	    reverse [x]	= [x]
> +	reverse (xs+ys)	= reverse ys + reverse xs
> +   reverse (reverse xs)	= xs
> +</H4>
> +To test whether 2nd rule holds for testrev(), define the invariant 
> +function as :
> +<H4>
> +	testing(Xs, Ys) =
> +        	testrev(Xs ++ Ys) `===` (testrev(Ys) ++ testrev(Xs)).
> +</H4>
> +`===` function returns 'property:[yes]' if the left side equals 
> +right side, 'property:[no]' otherwise. ( like == in Haskell, but not of 
> +type bool)

The comparison with '==' is probably not necessary, since you have just
described what the function actually does.

In theory testrev/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>	
> +	:- func testing(list(int), list(int)) = property.
> +				Or
> +	:- func testing(list(char), list(char)) = property.
> +</H4>
> +Now define the main() as

s,the main(),main/2,

> +<H4>
> +	Main --- >

s/Main/main/

and also below.

> +		qcheck(qcheck_f(testing), "sample testing").
> +</H4>
> +The complete use.m looks like this:
> +<P>
> +<table border=0 width=100% bgcolor=#eeeee0><tr><td><pre>
> +
> +:- module use.
> +
> +:- interface.
> +
> +:- use_module io.
> +
> +:- pred main(io__state, io__state).
> +:- mode main(di, uo) is det.
> +
> +%-------------------------------------------------------------------%
> +
> +:- implementation.
> +
> +:- import_module int, list.
> +:- import_module qcheck, testrev.
> +
> +%-------------------------------------------------------------------%
> +
> +main -->
> +     	qcheck(qcheck__f(testing), "sample testing").
> +
> +%-------------------------------------------------------------------%
> +% 	Invariant test functions
> +%-------------------------------------------------------------------%
> +
> +:- func testing(list(int), list(int)) = property.
> +testing(Xs, Ys) = 
> +	testrev(Xs ++ Ys) `===` (testrev(Ys) ++ testrev(Xs)).
> +</pre></tr></table>
> +To compiler the program, do "mmake use.depend", then "mmake use".

s/compiler/compile/

> +After running, the statistics should be displayed like :
> +<H4>
> +	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>
> +testrev/1 passed 100 tests and failed none.(ignore the last 3 lines
> +for now)

The full-stop should go at the end, to make this a correct sentence.

> +
> +If the invariant function is wrongly specified, or testrev/1 is not 
> +properly implemented, then the statistics may look like :
> +<H4>
> +	Test description : sample testing
> +	Falsifiable : 
> +	[2]
> +	[-2, 1]
> +</H4>
> +where running [2] as Xs and [-2, 1] as Ys failed the invariant function. 
> +
> +Defining an invariant function which contains only functions is cleaner 

The meaning of the word "cleaner" is not clear.  I would say "more
concise" instead.

> +(as in Haskell) than one which contains predicates. Suppose that "testrev2.m" 

I'm not sure how this relates to Haskell.  I would remove the "(as in
Haskell)".

> +defines a predicate version of reversing list: 
> +<P>
> +<table border=0 width=100% bgcolor=#eeeee0><tr><td><pre>
> +	:- pred testrev2(list(T), list(T)).
> +	:- mode testrev2(in, out) is det.
> +	testrev2([], []).
> +	testrev2([X|Xs], Ys):- 
> +		testrev2(Xs, Reversed), 
> +		list__append(Reversed, [X], Ys).
> +</pre></tr></table>
> +Then the invariant function looks like : 
> +<h4>
> +	testing2(Xs, Ys) = (Left `===` Right) :-
> +		testrev2((Xs ++ Ys), Left),
> +		testrev2(Ys, Part_a),
> +		testrev2(Ys, Part_b),
> +		Right = Part_a ++ Part_b.
> +</h4>
> +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>
> +:- module use1.
> +
> +:- interface.
> +
> +:- use_module io.
> +
> +:- pred main(io__state, io__state).
> +:- mode main(di, uo) is det.
> +
> +%-------------------------------------------------------------------%
> +
> +:- implementation.
> +
> +:- import_module int, list.
> +:- import_module qcheck, testrev2.
> +
> +%-------------------------------------------------------------------%
> +
> +main -->
> +     	qcheck(qcheck__f(testing2), "testing2").
> +
> +%-------------------------------------------------------------------%
> +% 	Invariant test functions
> +%-------------------------------------------------------------------%
> +
> +:- func testing2(list(int), list(int)) = property.
> +testing2(Xs, Ys) = (Left `===` Right) :-
> +	testrev2((Xs ++ Ys), Left),
> +	testrev2(Ys, Part_a),
> +	testrev2(Xs, Part_b),
> +	Right = Part_a ++ Part_b.
> +</pre></tr></table>
> +An alternative to write use.m which does not evolving writing a separate 
> +invariant function, (use11.m):
> +<P>
> +<table border=0 width=100% bgcolor=#eeeee0><tr><td><pre>
> +:- module use11.
> +
> +:- interface.
> +
> +:- use_module io.
> +
> +:- pred main(io__state, io__state).
> +:- mode main(di, uo) is det.
> +
> +%--------------------------------------------------------------------------%
> +
> +:- implementation.
> +
> +:- import_module int, list.
> +:- import_module qcheck, testrev.
> +
> +%--------------------------------------------------------------------------%
> +
> +main -->
> +    qcheck(qcheck__f(func(Xs `with_type` list(int), Ys `with_type` list(int))
> +		     = testrev(Xs ++ Ys) `===` (testrev(Ys) ++ testrev(Xs))),
> +           "sample testing").
> +</pre></tr></table>

This is a fairly normal use of higher order code, and probably doesn't
need its own example.

> +Summary 
> +
> +In YYY.m, the main should be defined as :
> +<h4>
> +	Main --->
> +		qcheck(qcheck_f(XXXXXXXX), YYYYYYYY).
> +</h4>

You should use more meaningful variable names than these.  The same
applies for other places in the tutorials.

> +Where XXXXXXXX is the (name of) invariant function and

XX... is a higher order term which represents the invariant.  It doesn't
necessarily have to be the function name, as your last example shows.

> +YYYYYYYY is a string which describe/name/comment XXXXXXXX.
> +
> +The invariant function is of the form 
> +<h4>
> +	:- mode XXXXXXXX(in, in, in ...) = out.
> +</h4>
> +The inputs can be of any type. The output is of type 'property:[yes]' or 'peoperty:[no]'

s/peoperty/property/

That is the _value_ of the output, not the type.  Also, the list can
have other flags as well -- it doesn't have to be just [yes] or [no].

You should mention that there can be any number of inputs (up to a
certain fixed limit).

> +What ever happens inside XXXXXXXX, quickcheck does not care.  If output is [yes], the 
> +invariant function is assumed to pass the test case satisfactory.

I would write:

	If the output list contains `yes', then the invariant is assumed
	to be satisfied.

> + 
> +
> +</html>
> Index: quickcheck/tutes/T2.html
> ===================================================================
> RCS file: T2.html
> diff -N T2.html
> --- /dev/null	Wed Nov 15 09:24:47 2000
> +++ T2.html	Mon Feb  5 16:01:53 2001
> @@ -0,0 +1,133 @@
> +<html>
> +<head> 
> +	<TITLE> QuickCheck </TITLE>
> +</head>
> +<H1> QuickCheck Tutorial 2 </H1>
> +Files : 
> +<a href="use20.m">use20.m</a>
> +<a href="use21.m">use21.m</a>
> +<a href="mymax.m">mymax.m</a><BR>
> +<a href="index.html">Back to main</a>
> +<h3> Conditional law </h3>
> +
> +<pre>
> +Conditional law 

No need to repeat that line.

> +In general many laws hold only under certain conditions, Quickcheck provides
> +an implication combinator to represent such conditional laws.

That is really two sentences, not one, so

s/, /.  /

Eg, the law 
> +	X <= Y  => max x y == y 

To be less ambiguous, write less-than-or-equal-to as '=<' instead of '<='.

> +can be represented by the definition :
> +<h4>
> +	:- func law(int, int) = property.
> +	law(X, Y) = (X =< Y) `===>` (mymax(X, Y) `===` Y).
> +</h4>
> +or alternatively can be represented as :
> +<h4>
> +	:- func law2(int, int) = property.
> +	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
> +	  	 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.
> + 
> +    
> +The complete use20.m :
> +<P>
> +<table border=0 width=100% bgcolor=#eeeee0><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 -->
> +     	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).
> +
> +:- func law2(int, int) = property.
> +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
> +  	 then
> +		Bool = yes
> +	 else
> +		Bool = no
> +	).
> +</pre></tr></table>
> +After running the program, test statistics will be something like:
> +<h4>
> +	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
> +	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>
> +The default number of tests to run is 100, in the above test only 48/100
> +passed the invariant function, and none failed. However, 52/100 cases where
> +the inputs failed the prec-condition.

That is not a complete sentence.

s/prec-condition/pre-condition/

> +Note that both test cases succeeded 52/100 and failed pre-condition 48/100. 
> +This is not a coincident; 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.  

s/coincident/coincidence/

Note that "coincidence" also means the fact of happening at the same
time, so this is probably a bad choice of words.

> +
> +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>
> +	:- func law(int, int) = property.
> +	law(X, Y) =  notzero(Y) `===>` ((X =< Y) `===>` (mymax(X, Y) `===` Y)).
> +
> +	:- pred notzero(int).
> +	:- mode notzero(in) is semidet.
> +	notzero(X) :- X \= 0.
> +</h4>	 
> +
> +Summary:
> +<P>
> +<table border=0 width=100% bgcolor=#eeeee0><tr><td><pre>
> +	:- type property == list(flag).
> +
> +	:- type flag 
> +		--->	yes
> +		;	no	
> +		;	trivial
> +		;	info(univ)	
> +		;	condition.
> +</pre></tr></table>
> +All invariant functions must return a property, which is just a list of flags.

This isn't a summary, since it is introducing new material.  I think
these comments should be much earlier in the tutorial, when invariant
functions are first introduced.

> +If the list contains one or more 'condition', the test result is ignored.
> +The implication combinator '===>' will add 'condition' into the property if
> +its left argument is '(pred):fail' or 'bool:no'. 
> +</html>
> \ No newline at end of file
> Index: quickcheck/tutes/T3.html
> ===================================================================
> RCS file: T3.html
> diff -N T3.html
> --- /dev/null	Wed Nov 15 09:24:47 2000
> +++ T3.html	Mon Feb  5 16:01:53 2001
> @@ -0,0 +1,292 @@
> +<html>
> +<head> 
> +        <TITLE> QuickCheck </TITLE>
> +</head>
> +<H1> QuickCheck Tutorial 3 </H1>
> +Files : 
> +<a href="use31.m">use31.m</a>
> +<a href="use33.m">use33.m</a>
> +<a href="testrev.m">testrev.m</a><BR>
> +<a href="index.html">Back to main</a>
> +<h3> Monitoring Test Data - to_trivial/3 </h3>
> +
> +<pre>
> +In Tutorial 1, the 3rd rule for reverse is that: 
> +	reverse (reverse xs) = xs
> +It's not much of a test if xs is empty list or list with only 1 element.
> +
> +Quickcheck can label a test being trivial via the function 
> +to_trivial(), 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>
> +	:- func testing1(list(float)) = property.
> +	testing1(Xs) = 
> +		testrev (testrev Xs) `===` Xs.
> +</h4>
> +add to_trivial([], Xs, XXXXXX) where XXXXXX is the ordinary output.

Please write that as a complete sentence.

If the 1st 
> +argument is equal to the 2nd argument, then that test case is labeled trivial, 
> +in this case, an empty list.
> +<h4>	
> +	:- func testing2(list(float)) = property.
> +	testing2(Xs) = 
> +		to_trivial([], Xs, testrev (testrev Xs) `===` Xs).
> +</h4>
> +Use compounded to_trivial to also classify list of 1 element as trivial 
> +<h4>
> +	:- func testing3(list(float)) = property.
> +	testing3(Xs) = 
> +                to_trivial(1, 
> +                           list_length(Xs), 
> +                           to_trivial([], Xs, testrev(testrev(Xs)) `===` Xs)
> +                          ).
> +</h4>
> +The complete code (use31.m) :
> +<P>
> +<table border=0 width=100% bgcolor=#eeeee0><tr><td><pre>
> +:- module use31.
> +
> +:- 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, testrev.
> +
> +%---------------------------------------------------------------------------%
> +
> +main -->
> +     	qcheck(qcheck__f(testing1), "testing1"),
> +     	qcheck(qcheck__f(testing2), "testing2"),
> +     	qcheck(qcheck__f(testing3), "testing3").
> +
> +:- func testing1(list(float)) = property.
> +testing1(Xs) = 
> +	testrev(testrev(Xs)) `===` Xs.
> +	
> +:- func testing2(list(float)) = property.
> +testing2(Xs) = 
> +	to_trivial([], Xs, testrev(testrev(Xs)) `===` Xs).
> +
> +:- func testing3(list(float)) = property.
> +testing3(Xs) = 
> +	to_trivial(1, 
> +		   list_length(Xs), 
> +                   to_trivial([], Xs, testrev(testrev(Xs)) `===` Xs)
> +		  ).
> +</pre></tr></table>
> +A sample output :
> +<h4>
> +	Test Description : testing1
> +	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) : 
> +
> +	Test Description : testing2
> +	Number of test cases that succeeded : 100
> +	Number of trivial tests : 53
> +	Number of tests cases which failed the pre-condition : 0
> +	Distributions of selected argument(s) : 
> +
> +	Test Description : testing3
> +	Number of test cases that succeeded : 100
> +	Number of trivial tests : 75
> +	Number of tests cases which failed the pre-condition : 0
> +	Distributions of selected argument(s) : 
> +</h4>
> +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 empty lists or 
> +lists of only one element.

s/either empty lists or lists/either an empty list or a list/

It had only tested 25/100 cases where the list is 
> +longer than 1 element. 

s/had //

> +
> +
> +<h3> Monitoring Test Data - `>>>` </h3>
> +The combinator `>>>` will gather all values that are passed to it, and prints out 
> +a histogram of these values.

s/will gather/gathers/

> +Let's use `>>>` to find out exactly what lists are generate for the previous tests :

s/generate/generated/

> +<h4>
> +	:- func testing4(list(float)) = property.
> +	testing4(Xs) = 
> +		list_length(Xs) `>>>` (testrev(testrev(Xs)) `===` Xs).
> +</h4>
> +The combinator `>>>` will convert it's left argument to a univ, and push info(univ) 

s/it's/its/

> +into it's right argument(which is a property == a list of flags).

It would be better to say "into the property list".

> +The complete code (use31.m) :
> +<P>
> +<table border=0 width=100% bgcolor=#eeeee0><tr><td><pre>
> +:- module use31.
> +
> +:- 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, testrev.
> +
> +%---------------------------------------------------------------------------%
> +
> +main -->
> +     	qcheck(qcheck__f(testing1), "testing1"),
> +     	qcheck(qcheck__f(testing2), "testing2"),
> +     	qcheck(qcheck__f(testing3), "testing3"),
> +     	qcheck(qcheck__f(testing4), "testing4").
> +
> +:- func testing1(list(float)) = property.
> +testing1(Xs) = 
> +	testrev(testrev(Xs)) `===` Xs.
> +	
> +:- func testing2(list(float)) = property.
> +testing2(Xs) = 
> +	to_trivial([], Xs, testrev(testrev(Xs)) `===` Xs).
> +
> +:- func testing3(list(float)) = property.
> +testing3(Xs) = 
> +	to_trivial(1, 
> +		   list_length(Xs), 
> +                   to_trivial([], Xs, testrev(testrev(Xs)) `===` Xs)
> +		  ).
> +
> +:- func testing4(list(float)) = property.
> +testing4(Xs) = 
> +	list_length(Xs) `>>>` (testrev(testrev(Xs)) `===` Xs).
> +</pre></tr></table>
> +A sample output :
> +<h4>
> +Test Description : testing1
> +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) : 
> +
> +Test Description : testing2
> +Number of test cases that succeeded : 100
> +Number of trivial tests : 53
> +Number of tests cases which failed the pre-condition : 0
> +Distributions of selected argument(s) : 
> +
> +Test Description : testing3
> +Number of test cases that succeeded : 100
> +Number of trivial tests : 71
> +Number of tests cases which failed the pre-condition : 0
> +Distributions of selected argument(s) : 
> +
> +Test Description : testing4
> +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) : 
> +1     8
> +1     4
> +1     6
> +2     5
> +8     3
> +16     2
> +18     1
> +53     0
> +</h4>
> +The display of testing4 shows that 	53 cases of lenggh == 0

s/length/lenggh/

> +					18 cases of length == 1
> +					16 cases of length == 2
> +					...etc...	
> +53+18 cases = 71 cases, which was marked trivial in testing3, likewise

s/was/were/

> +for testing2. The number will add up only if all the tests were ran within
> +the same second.

s/number/numbers/
s/ran/run/

I would write "with the same random number seed" rather than "within the
same second", otherwise the reason for this might not be clear.

> +
> +
> +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>
> +:- module use33.
> +
> +:- 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, testrev.
> +
> +%---------------------------------------------------------------------------%
> +
> +main -->
> +     	qcheck(qcheck__f(testing5), "testing5").
> +
> +:- func testing5(list(float)) = property.
> +testing5(Xs) = 
> +	odd_even(Xs) `>>>` 
> +                     (list_length(Xs) `>>>` (testrev(testrev(Xs)) `===` Xs)).
> +
> +:- func odd_even(list(T)) = string.
> +:- mode odd_even(in) = out is det.
> +odd_even(Xs) = Y :-
> +	(if	list_length(Xs) mod 2 = 1
> +	 then
> +		Y = "odd"
> +	 else
> +		Y = "even"
> +	).
> +</pre></tr></table>
> +testing5 collects the list_length, and also collect "odd" or "even"
> +A sample output :
> +<h4>
> +Test Description : testing5
> +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) : 
> +1     7
> +1     5
> +2     4
> +2     6
> +8     3
> +10     2
> +29     1
> +39     "odd"
> +47     0
> +61     "even"
> +</h4>

I think the following point is self evident.

> +The display of testing5 shows that 	61 cases of "even"
> +					47 cases of length == 0
> +					39 cases of "odd"
> +					...etc...	

You can leave off the following, since it is not particularly relevant
to a tutorial.

> +Currently the display is sorted by the number of occurences, without any regards to 
> +the type.
> +<h4>
> +1	7
> +1	5
> +2	4
> +2	6
> +8	3
> +1	B
> +1	A
> +2	C
> +10	Z
> +</h4>
> +May implement to above display later....
> +
> +
> +
> +
> + 
> +

To be continued ...

--------------------------------------------------------------------------
mercury-developers mailing list
Post messages to:       mercury-developers at cs.mu.oz.au
Administrative Queries: owner-mercury-developers at cs.mu.oz.au
Subscriptions:          mercury-developers-request at cs.mu.oz.au
--------------------------------------------------------------------------



More information about the developers mailing list