[Haskell-cafe] quickCheck problem

26 views
Skip to first unread message

Roelof Wobben

unread,
Oct 6, 2015, 4:24:01 PM10/6/15
to haskel...@haskell.org
Hello,

I have written a function to test if three numbers are the same.

Now I want to test my functions by using quickCheck.

So I thought to test first if all three are the same.

but how can I tell quickcheck that all numbers are the same.

and second question : hwo do the test likeif two numbers are the same.

I ask this because I try to solve a exercise of the programming Haskell
book,
IM have read chapter 3 now.

Roelof

_______________________________________________
Haskell-Cafe mailing list
Haskel...@haskell.org
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe

Rogan Creswick

unread,
Oct 6, 2015, 4:31:53 PM10/6/15
to Roelof Wobben, haskell-cafe
On Tue, Oct 6, 2015 at 1:24 PM, Roelof Wobben <r.wo...@home.nl> wrote:
> Hello,
>
> I have written a function to test if three numbers are the same.
>
> Now I want to test my functions by using quickCheck.
>
> So I thought to test first if all three are the same.
>
> but how can I tell quickcheck that all numbers are the same.

Just have quickcheck generate one number, and use it for all three
arguments, eg:

prop_allSame :: Int -> Bool
prop_allSame x = yourFn x x x

then test the other cases:

prop_different :: Int -> Int -> Int -> Property
prop_different x y z = x /= y && y /= z && x /= z ==> not $ yourFn x y z

That's probably OK for ints, but generally the guard in that style
isn't a great solution, since quickcheck will just keep generating
inputs until the predicate is satisfied. That can take a while, so
you could also manually offset the first input in various ways:

prop_different :: Int -> Int -> Bool
prop_different x y = not $ yourFn x (x + y) (x - (y + 1)) -- I put a
+1 in here to avoid returning true where y = 0,

There are probably other ways to mutate a randomly generated input for
your problem that may work better, but that's the general idea.

--Rogan

Roelof Wobben

unread,
Oct 6, 2015, 5:01:42 PM10/6/15
to haskel...@haskell.org
Thanks,

but why this part :

x (x + y) (x - (y + 1))


Roelof

Op 6-10-2015 om 22:31 schreef Rogan Creswick:
> -----
> Geen virus gevonden in dit bericht.
> Gecontroleerd door AVG - www.avg.com
> Versie: 2015.0.6140 / Virusdatabase: 4435/10768 - datum van uitgifte: 10/06/15

Rogan Creswick

unread,
Oct 6, 2015, 6:28:47 PM10/6/15
to Roelof Wobben, haskell-cafe
On Tue, Oct 6, 2015 at 2:01 PM, Roelof Wobben <r.wo...@home.nl> wrote:
> but why this part :
>
> x (x + y) (x - (y + 1))

That is buggy. I was trying to quickly create three arguments that
are guaranteed to be different by some random amount, but what I wrote
doesn't always work (eg: if y = 0, then the first two arguments are
the same, if y is -1, the first and 3rd are the same, if x is MAX_INT,
then it may or may not be the same as other arguments, depending on Y,
etc...)

The predicate guard should work, though it may take longer to run.

--Rogan

Roelof Wobben

unread,
Oct 7, 2015, 3:12:59 AM10/7/15
to haskell-cafe
Maybe im on the wrong track now.

I know that if three numbers are the same then the outcome will be false.
The same if two numbers are the same.

Can I not do something like this :

prop_different x y z = not( (x /= y && y /= z && x /= z))

to test all cases at once.

Roelof



Op 7-10-2015 om 00:28 schreef Rogan Creswick:

Bryan Richter

unread,
Oct 7, 2015, 12:16:06 PM10/7/15
to haskel...@haskell.org
On Tue, Oct 06, 2015 at 10:24:03PM +0200, Roelof Wobben wrote:
> Hello,
>
> I have written a function to test if three numbers are the same.
>
> Now I want to test my functions by using quickCheck.
>
> So I thought to test first if all three are the same.
>
> but how can I tell quickcheck that all numbers are the same.

Easy, just generate a single number. :) Make it correct by
construction.

prop_allSame x =
yourFunc x x x == True

> and second question : hwo do the test likeif two numbers are the same.

Now the hard part is not generating two numbers that are the same, but
generating two *different* numbers. To do that you may need to create
a custom generator.

unequalPair = do
x <- arbitrary
y <- arbitrary `suchThat` y /= x
return (x,y)

Now you can use that generator:

prop_twoSame = forAll unequalPair $ \(x,y) ->
yourFunc x x y == False
-- But you might want to test all permutations!
signature.asc

Rogan Creswick

unread,
Oct 7, 2015, 12:32:26 PM10/7/15
to Roelof Wobben, haskell-cafe
On Wed, Oct 7, 2015 at 12:13 AM, Roelof Wobben <r.wo...@home.nl> wrote:
> I know that if three numbers are the same then the outcome will be false.
> The same if two numbers are the same.
>
> Can I not do something like this :
>
> prop_different x y z = not( (x /= y && y /= z && x /= z))
>
> to test all cases at once.

That looks like it will work (I'm assuming you're actually calling
your function in the property and comparing with that boolean
expression); is that the same way your function is implemented?

--Rogan

Roelof Wobben

unread,
Oct 7, 2015, 1:01:13 PM10/7/15
to haskell-cafe
Op 7-10-2015 om 18:32 schreef Rogan Creswick:
> On Wed, Oct 7, 2015 at 12:13 AM, Roelof Wobben <r.wo...@home.nl> wrote:
>> I know that if three numbers are the same then the outcome will be false.
>> The same if two numbers are the same.
>>
>> Can I not do something like this :
>>
>> prop_different x y z = not( (x /= y && y /= z && x /= z))
>>
>> to test all cases at once.
> That looks like it will work (I'm assuming you're actually calling
> your function in the property and comparing with that boolean
> expression); is that the same way your function is implemented?
>
> --Rogan
>

Unfortanally yes but I do not know another way to test it.
Im only a beginner which has read 2 chapters of the Crafts book.

Rogan Creswick

unread,
Oct 7, 2015, 2:25:41 PM10/7/15
to Roelof Wobben, haskell-cafe
On Wed, Oct 7, 2015 at 10:01 AM, Roelof Wobben <r.wo...@home.nl> wrote:
> Op 7-10-2015 om 18:32 schreef Rogan Creswick:
>>
>> On Wed, Oct 7, 2015 at 12:13 AM, Roelof Wobben <r.wo...@home.nl> wrote:
>>>
>>> I know that if three numbers are the same then the outcome will be false.
>>> The same if two numbers are the same.
>>>
>>> Can I not do something like this :
>>>
>>> prop_different x y z = not( (x /= y && y /= z && x /= z))
>>>
>>> to test all cases at once.
>>
>> That looks like it will work (I'm assuming you're actually calling
>> your function in the property and comparing with that boolean
>> expression); is that the same way your function is implemented?
>>
>> --Rogan
>>
>
> Unfortanally yes but I do not know another way to test it.
> Im only a beginner which has read 2 chapters of the Crafts book.

Then I'd suggest using the quickcheck property guards ( `==>`) to only
generate inputs that are known to be equal, or not equal and test
separately in a few different properties.

--Rogan

Ozgur Akgun

unread,
Oct 7, 2015, 2:33:59 PM10/7/15
to Rogan Creswick, haskell-cafe
On 7 October 2015 at 19:25, Rogan Creswick <cres...@gmail.com> wrote:
Then I'd suggest using the quickcheck property guards ( `==>`) to only
generate inputs that are known to be equal, or not equal and test
separately in a few different properties.

This is not true, ==> still does generate and test.

Prelude> import Test.QuickCheck
Prelude Test.QuickCheck> let f x = x == 13 ==> mod x 2 == 1
Prelude Test.QuickCheck> quickCheck f
*** Gave up! Passed only 6 tests. 

Also try verboseCheck to see what values are generated.

Ozgur

Rogan Creswick

unread,
Oct 7, 2015, 2:39:57 PM10/7/15
to Ozgur Akgun, haskell-cafe
On Wed, Oct 7, 2015 at 11:33 AM, Ozgur Akgun <ozgur...@gmail.com> wrote:
> This is not true, ==> still does generate and test.

I could have phrased that better. Sure, it generates values, but it
will never provide them to your test, so your logic is simpler.

> Prelude> import Test.QuickCheck
> Prelude Test.QuickCheck> let f x = x == 13 ==> mod x 2 == 1
> Prelude Test.QuickCheck> quickCheck f
> *** Gave up! Passed only 6 tests.

That's unlikely to be a problem given the test inputs in the original
question, but yes, it is certainly an issue to know about.

Roelof -

The issue Ozgur is demonstrating is that the ==> operator will just
discard test inputs that were generated but which did not satisfy the
predicate (here that x == 13). QuickCheck will eventually stop trying
to generate inputs (you can tune this), and produce something like the
above result.

--Rogan

>
> Also try verboseCheck to see what values are generated.
>
> Ozgur
>

Richard A. O'Keefe

unread,
Oct 7, 2015, 7:16:26 PM10/7/15
to Rogan Creswick, haskell-cafe
You can generate two unequal integers by doing

prop_twoDifferent :: Int -> Int -> Bool
prop_twoDifferent x y = yourFn2 x y'
where y' = if y >= x then y+1 else y

Letting the number of distinct Int values be N,
there are N*N pairs of Ints but only N*(N-1) pairs of
*different* Ints, so this technique will generate some
x y' pairs more often than others. In fact you will
get (x,minBound::Int) with probability 2/N and
(x,y>minBound) with probability 1/N.
The advantage of using a guard is that the probabilities
come out right (it's the "rejection method", in
statistical parlance).

You can use that method to generate
x x y
x y x
y x x

You can iterate the same idea to generate triples.

Roelof Wobben

unread,
Oct 8, 2015, 1:03:44 AM10/8/15
to haskell-cafe
Op 8-10-2015 om 01:16 schreef Richard A. O'Keefe:
> You can generate two unequal integers by doing
>
> prop_twoDifferent :: Int -> Int -> Bool
> prop_twoDifferent x y = yourFn2 x y'
> where y' = if y >= x then y+1 else y
>
> Letting the number of distinct Int values be N,
> there are N*N pairs of Ints but only N*(N-1) pairs of
> *different* Ints, so this technique will generate some
> x y' pairs more often than others. In fact you will
> get (x,minBound::Int) with probability 2/N and
> (x,y>minBound) with probability 1/N.
> The advantage of using a guard is that the probabilities
> come out right (it's the "rejection method", in
> statistical parlance).
>
> You can use that method to generate
> x x y
> x y x
> y x x
>
> You can iterate the same idea to generate triples.
>
>
>
> -----
> Geen virus gevonden in dit bericht.
> Gecontroleerd door AVG - www.avg.com
> Versie: 2015.0.6140 / Virusdatabase: 4435/10775 - datum van uitgifte: 10/07/15
>
>

Thanks all.

Enough to study and try.

Roelof
Reply all
Reply to author
Forward
0 new messages