Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Law-abiding instances for Arbitrary (Equivalence a) and Arbitrary (Comparison a) #47

Open
Zemyla opened this issue Dec 30, 2019 · 0 comments

Comments

@Zemyla
Copy link

Zemyla commented Dec 30, 2019

(Copied from nick8325/quickcheck#280 )

Data.Functor.Contravariant is now in base, and it includes the types

newtype Equivalence a = Equivalence { getEquivalence :: a -> a -> Bool }
newtype Comparison a = Comparison { getComparison :: a -> a -> Ordering }

and those would be really useful to generate for CoArbitrary, for sort predicates and such. However, the standard Arbitrary instance for them would not be useful, because they don't abide by the reflexivity, symmetry/antisymmetry, and transitivity laws at all.

However, I think I found a way. A CoArbitrary type can be sort of "hashed" by using it on a Gen:

cohash :: CoArbitrary a => QCGen -> Int -> a -> Int
cohash g n a = unGen (coarbitrary a $ MkGen $ \g0 n0 -> fst $ randomR (negate n0, n0) g0) g n

Here, the "size" of the generator represents the "fineness" of the hash.

With that, we can generate the instances as follows:

instance CoArbitrary a => Arbitrary (Equivalence a) where
  arbitrary = MkGen $ \g n -> Equivalence $ \a b -> cohash g n a == cohash g n b

instance CoArbitrary a => Arbitrary (Comparison a) where
  arbitrary = MkGen $ \g n -> Comparison $ \a b -> compare (cohash g n a) (cohash g n b)

(Incidentally, the type Predicate also exists, but can be generated with the standard instance for a -> Bool.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant