Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to generate arbitrary instances of a simple type for quickcheck

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?

like image 306
liammclennan Avatar asked May 08 '13 12:05

liammclennan


2 Answers

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.

like image 74
hammar Avatar answered Nov 06 '22 10:11

hammar


You can generate an Arbitrary instance doing the same using TemplateHaskell and derive package:

import Data.DeriveTH

derive makeArbitrary ''Cell
like image 42
Koterpillar Avatar answered Nov 06 '22 11:11

Koterpillar