How to generate arbitrary instances of a simple type for quickcheck

liammclennan picture liammclennan · May 8, 2013 · Viewed 10.7k times · Source

I have a simple type definition:

data Cell = Cell {
    x       :: Int,
    y       :: Int
  } deriving (Show)

I can't use Cell as an input to a quickcheck property, presumably because quickcheck doesn't know how to generate Cell values.

My understanding is that I need to make Cell an instance of the Arbitrary typeclass.

How do I do that, for example, if I'd like Cell to be generated with random positive values for x and y?

Answer

hammar picture hammar · May 8, 2013

Writing an instance of Arbitrary for your data type is easy. You just have to implement the arbitrary function, which should return a Gen Cell. The simplest way to do this is to make use of existing Arbitrary instances and also note that Gen is a monad, so we can use do-notation:

instance Arbitrary Cell where
   arbitrary = do
     Positive x <- arbitrary
     Positive y <- arbitrary
     return $ Cell x y

Alternatively, generators can often be written elegantly using operators from Control.Applicative:

instance Arbitrary Cell where
   arbitrary = Cell <$> pos <*> pos
     where pos = getPositive <$> arbitrary  -- getPositive requires QC >= 2.5

Here, I've also made use of the Positive modifier from Test.QuickCheck.Modifiers to ensure that we only generate positive integers.

For writing more complex generators, have a look at the various generators from Test.QuickCheck.Gen.