@@ -333,55 +333,39 @@ We can do a better job by constraining the condition using `genFromSpec`
333333spec1 :: Specification (Int ,Int ,Int ,Int )
334334spec1 = constrained' $ \ w x y z -> [w <. x, x <. y, y <. z]
335335
336- prop2 :: Gen Property
337- prop2 = do
338- ( w,x,y,z) <- genFromSpec spec1
339- pure $ (w < x && x < y && y < z) ==> property (w < z)
336+ prop2 :: Property
337+ prop2 =
338+ forAll (genFromSpec spec1) $ \ ( w,x,y,z)
339+ (w < x && x < y && y < z) ==> property (w < z)
340340```
341341
342- Now the test passes.
342+ Now the test passes!
343343
344344```
345345ghci> quickCheck prop2
346346+++ OK, passed 100 tests.
347347```
348348
349- Now this isn't a very good test either, since the precedent is alway true. A better solution would be to
350- generate a mix, where the precedent is True most of the time, but sometimes False. Like this.
349+ The second interpretation of the specification is as a constraint checker, implemented as the function.
351350
352351``` haskell
353- prop3 :: Gen Property
354- prop3 = do
355- (w,x,y,z) <- frequency [(9 ,genFromSpec spec1),(1 ,arbitrary)]
356- pure $ (w < x && x < y && y < z) ==> property (w < z)
357- ```
358-
359- Observe the result:
360-
361- ```
362- ghci> quickCheck prop3
363- +++ OK, passed 100 tests; 7 discarded.
352+ conformsToSpec :: HasSpec a => a -> Specification a -> Bool
364353```
365354
366- The ` 7 discarded ` arises because in most random samples of ` w ` , ` x ` , ` y ` , and ` z ` , the ordering constraint will
367- not be true, so a discard will occur. Because the ratio of constrained to random is 9 to 1, so the number
368- of failures is small enough that we don't ` give up ` . The role of the ` arbitrary ` is to guard against the possibility
369- that the constrained spec might be over constrained, and in that case will be values that will never be chosen in a random test.
370- Which means we will not be choosing a good sample of the test space, so some bugs might escape detection.
371- By adjusting the test so that any ` arbitrary ` samples, that are not ordered, pass the test, we identify
372- a piuntin the sample space that the code does not handle correctly. In a later section we discuss how to use
373- QuickChrck ` classify ` and ` cover ` write better tests.
374-
375- The purpose of constrained generators is to make it possible to write conditional 'implication' properties
376- that have a high probability of not being vacuously true, and to combine this with other random
377- techniques to make better samples of the test-space.
378-
379- The second interpretation of the specification is as a constraint checker, implemented as the function.
355+ Using this we can write a (admittedly silly) test that showcases this explicitly:
380356
381357```haskell
382- conformsToSpec :: HasSpec a => a -> Specification a -> Bool
358+ spec1 :: Specification (Int ,Int ,Int ,Int )
359+ spec1 = constrained' $ \ w x y z -> [w <. x, x <. y, y <. z]
360+
361+ prop2' :: Property
362+ prop2' =
363+ forAll (genFromSpec spec1) $ \ (w,x,y,z)
364+ (w,x,y,z) `conformsToSpec` spec1 ==> property (w < z)
383365```
384366
367+ Which similarly will always succeed and should never be discarded.
368+
385369## How we solve the constraints
386370
387371Before we continue delving into how we use the library and the finer points
0 commit comments