Search code examples
haskellquickcheck

Haskell QuickCheck generate random data for function with many input variables


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 choosebut 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.


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