
Joel Reymont
Would someone kindly explain why we need co-arbitrary in QuickCheck and how to define it?
Ever written a higher-order function and wanted to quickcheck it? So where do you get your random functional arguments from? Whereas the 'arbitrary' method allows you to write a generator for random values of a constructed datatype, the 'coarbitrary' method allows you to write a generator for random *functions* that take a randomly-generated value as argument, and produce a randomly-generated result that is nevertheless determined by / dependent on the argument.
Detailed examples would be awesome!
There are lots of instances already defined in Test.QuickCheck that are worth reading. In almost all cases they use the generator-combinator 'variant', which is like 'coarbitrary' but selects its result based on an Int rather than a value of an arbitrary datatype. So in most cases, implementing 'coarbitrary' amounts to converting the given argument to an appropriate Int to pass to 'variant'. instance Arbitrary Bool where coarbitrary b = if b then variant 0 else variant 1 The result type of 'corarbitrary' (and 'variant') :: Gen b -> Gen b means that, once some other part of the quickcheck apparatus has determined what the result type of the generated function should be (i.e. b), then given that we already have a random generator for one of those result values, what we are doing is *modifying* that result-generator to be dependent on the function's argument rather than entirely arbitrary. So in the Bool instance, 'coarbitrary' gives you a function-generator that picks a 0-based result-generator in the False case, or a 1-based result-generator in the True case. To write your own 'coarbitrary', you are aiming to convert values of your datatype into a disjoint partition of the set of all Ints. In the end it is rather mechanical: e.g. data Foo a = Foo String a | Bar Bool instance Arbitrary (Foo a) where coarbitrary (Foo s a) = variant 0 . coarbitrary s . coarbitrary a coarbitrary (Bar b) = variant 1 . coarbitrary b Regards, Malcolm