Haskell QuickCheck generates random data for a function with many input variables

I have a function with the following signature like

rndListIndex :: Double -> Double -> Double -> Double rndListIndex maxIdx r1 r2 = … 
  • the first input must be a value coming from a non-negative strictly positive integer
  • the second and third inputs must be within the interval [0.0,1.0], otherwise the function does not make sense

function has the property

 prop_alwaysLessThanMaxIdx idx r1 r2 = (rndListIndex idx r1 r2 <= idx) 

how to create random data for maxIdx and r1 , r2 separately; I know the choose function, but I don’t know how to use it with more than one input variable.

I have currently checked the Property with a fixed idx , which is not the way it should be checked.

+6
source share
2 answers

You must 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 create values. Examples of generators are choose , arbitrary , oneof , ...
  • The function checks the property for a given input. It should return a value that is an instance of Testable , for example, another Property , Bool or function.

An example of a nested forAll using select elements and elements:

 -- This generates a Property p for all x 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 a choice for the second and third arguments. For the first argument, QuickCheck has a type Positive a , which can be used to generate arbitrary positive values ​​of type a (it has an arbitrary instance when a has 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 
+12
source

I would suggest defining your own type, which wraps Double and gives it an Arbitrary instance that only generates numbers from 0 to 1. Something like:

 import Test.QuickCheck newtype UnitInterval = Unit Double deriving Show instance Arbitrary UnitInterval where arbitrary = fmap Unit (choose (0, 1)) shrink (Unit x) = [ Unit y | y <- shrink x, 0 <= y && y <= 1 ] 

You can use the QuickCheck Positive modifier to generate idx , as @bennoffs suggested (you will need to import Test.QuickCheck.Modifiers ). This is similar to the UnitInterval type described above, but generates positive numbers instead of numbers from 0 to 1. Then your property will look like this:

 prop_alwaysLessThanMaxIdx (Positive idx) (Unit r1) (Unit r2) = rndListIndex idx r1 r2 <= idx 
+1
source

Source: https://habr.com/ru/post/952380/


All Articles