How to generate arbitrary instances of a simple type for quickcheck
Asked Answered
G

2

39

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?

Generalization answered 8/5, 2013 at 12:3 Comment(1)
See also https://mcmap.net/q/409629/-generically-derive-arbitrary-for-massive-algebraic-data-types if you don't feel like writing instances.Uriisa
S
52

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.

Summarize answered 8/5, 2013 at 12:13 Comment(2)
This is where I would really like to use Applicative syntax instead.Sawn
Also, do consider writing an implementation for shrink. Less important here, perhaps, but saves so much effort for some cases.Cymry
F
16

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

import Data.DeriveTH

derive makeArbitrary ''Cell
Fulfillment answered 9/5, 2013 at 3:26 Comment(1)
You should mention where Data.DeriveTH comes from.Cymry

© 2022 - 2024 — McMap. All rights reserved.