QuickCheck: defining Arbitrary instance in terms of other Arbitraries
Asked Answered
C

1

12

I'm using QuickCheck 1 and I've got the following data types:

data A = ...
instance Arbitrary A where ...
data B = ...
instance Arbitrary B where ...
data C = C A B

Now I'd like to define an Arbitrary instance for C so that C values are generated using existing generators for A and B. I ended up doing this:

instance Arbitrary C where
  arbitrary = elements [(C a b) |
                        a <- generate 20 (System.Random.mkStdGen 0) arbitrary,
                        b <- generate 20 (System.Random.mkStdGen 0) arbitrary]

Is this explicit generation of a fixed number of values for A and B necessary, or is there a better way of combining existing Arbitraries into a new one?

Cud answered 27/2, 2011 at 16:13 Comment(1)
I think now (ghc 9.8.2 or later and perhaps earlier) you could just do: data C = C A B deriving (Arbitrary)Harden
N
21

I'd do it like this:

instance Arbitrary C
  where arbitrary = do a <- arbitrary
                       b <- arbitrary
                       return (C a b)

Although sclv's idea of using liftM2 from Control.Monad is probably better:

instance Arbitrary C
  where arbitrary = liftM2 C arbitrary arbitrary
Neighborhood answered 27/2, 2011 at 17:21 Comment(3)
arbitrary = C <$> arbitrary <*> arbitrary -- applicative ftw!Hoseahoseia
Makes sense, thanks! I like the applicative solution even more but sadly it doesn't work in QuickCheck 1 since Gen was not an instance of Applicative back then.Cud
sclv beat me to it. Applicatives can be very powerful and expressive.Venice

© 2022 - 2024 — McMap. All rights reserved.