[QuickCheck] Generic Arbitrary instance using GHC generics?

Bradford Larsen brad.larsen at gmail.com
Tue Dec 1 19:54:25 GMT 2015


I've recently been using QuickCheck, and was a bit surprised to find that I
have to manually define `Arbitrary` instances for all my data types.  In
simple cases, this probably shouldn't be necessary!

I searched for existing work on a generic `Arbitrary` instance, and found
only this Haskell Cafe thread from 2013:
https://groups.google.com/forum/#!topic/haskell-cafe/zaDyN9qHjeM.  One
comment there mentions an unmerged QuickCheck branch with generic Arbitrary
support, but I haven't found it.

Using GHC Generics, it seems relatively straightforward to define a generic
function for producing test inputs for QuickCheck.

Two questions:

   - Am I just overlooking already-existing generic Arbitrary support?
   - Are there pitfalls that I'm not aware of that make it difficult to add
   generic Arbitrary support?

Thanks,
Brad




A GHC Generics-based solution might look something like this:

class GArbitrary f where

  garbitrary :: Gen (f a)





instance GArbitrary V1 where

  garbitrary = undefined




instance GArbitrary U1 where

  garbitrary = pure U1




instance (Generic c, GArbitrary (Rep c)) => GArbitrary (K1 i c) where

  garbitrary = K1 . to <$> garbitrary



-- Note: this instance doesn't evenly select from sums with more

-- than 2 constructors


instance (GArbitrary f, GArbitrary g) => GArbitrary (f :+: g) where


  garbitrary = oneof [ L1 <$> garbitrary, R1 <$> garbitrary ]





instance (GArbitrary f, GArbitrary g) => GArbitrary (f :*: g) where

  garbitrary = (:*:) <$> garbitrary <*> garbitrary





instance (GArbitrary f) => GArbitrary (M1 i c f) where


  garbitrary = M1 <$> garbitrary





instance (GArbitrary f, GArbitrary g) => GArbitrary (f :.: g) where


  garbitrary = Comp1 <$> garbitrary





genericArbitrary :: (GArbitrary (Rep a), Generic a) => Gen a


genericArbitrary = fmap to garbitrary


Then, we could add a default signature for `arbitrary` in QuickCheck's
`Arbitrary` class, using `genericArbitrary`, and automatically generate
test cases for many data types.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://projects.haskell.org/pipermail/quickcheck/attachments/20151201/f73c0cf8/attachment.htm>


More information about the QuickCheck mailing list