Haskell QuickCheck generate random data for function with many input variables

haskell, quickcheck

Solution

You have to use the forAll function from QuickCheck. It has the following type:

forAll :: (Show a, Testable prop) 
       => Gen a           -- ^ The generator to use for generating values
       -> (a -> prop)     -- ^ A function which returns a testable property
       -> Property                  

`forAll` takes two arguments:

- The generator describes how to generate values. Examples of generators are choose, arbitrary, oneof, ...

- The function tests the property for the given input. It must return a value that is an instance of `Testable`, for example another `Property`, `Bool` or a function.

Example of a nested forAll with the choose and elements generators:

-- This generates a Property p for all x's in the closed interval [1,3]
-- The property p in turn generates a property q for all y ∈ [4,5]
-- The property q is True if x < y.
prop_choose = forAll (choose (1,3)) $ \x ->
              forAll (elements [4,5]) $ \y -> x < y

For your test property, you can use forAll with choose for the second and third argument. For the first argument, there is the `Positive a` type in QuickCheck which can be used to generate arbitrary positive values of type a (It has an Arbitrary instance when a is a Num):

prop_alwayLessThanMaxIdx :: Positive Integer -> Property
prop_alwaysLessThanMaxIdx (Positive idx) = 
  forAll (choose (0,1)) $ \r1 ->
  forAll (choose (0,1)) $ \r2 ->
   (rndListIndex idx r1 r2) < idx

Problem

I have a function with the following type signature ``` rndListIndex :: Double -> Double -> Double -> Double rndListIndex maxIdx r1 r2 = … ``` - the first input should be a value coming from a non-negative strictly positive integer - the second and third input are required to be within the closed interval [0.0,1.0] otherwise the function makes no sense the function has the property of ``` prop_alwaysLessThanMaxIdx idx r1 r2 = (rndListIndex idx r1 r2 <= idx) ``` how do I generate random data for `maxIdx` and `r1`,`r2` separately; I know of the function `choose`but do not know how to use it with more than one input variable. For now I have tested the Property with fixed `idx`, which is not the way it should be tested.

Original source