4

Does anyone know exactly how to define a generator in Haskell using QuickCheck such that chosen elements are picked only ONCE?

I've gotten as far as realizing that I might need a "Gen (Maybe Positive)" generator, but of course that will generate number with repetition. I want it so that the numbers chosen are picked without repetition. In the instance when a number is returned I want Just returned and in the instance where the randoms are all exhausted I want Gen Nothing returned.

Thanks,

Mark

Mark
  • 41
  • 2

3 Answers3

5

You can't. Look at the definition of Gen. There's no way for it to carry any state about what has been picked so far. Given the same random generator and size limit it must always generate the same result. You can however write a Eq a => Gen [a] that generates a list of values with no repetitions. A simple (but somewhat naive) one would be something like this.

uniques :: Eq a => Gen a -> Gen [a]
uniques gen = fmap nub $ listOf gen
hammar
  • 138,522
  • 17
  • 304
  • 385
  • 2
    The xorshift random generator has no repetitions by design. You could try it. (the statement above holds for the first 2^64 or so numbers. – fuz Jul 26 '11 at 13:28
  • Hrm. I thought that it might be possible to pick a different generator each time using CoArbitrary (somehow?) with the range restricted/constrained – Mark Jul 26 '11 at 13:56
3

QuickCheck is generally for randomized testing, not exhaustive testing. There are a few great libraries that do handle exhaustive testing -- look at smallcheck and lazysmallcheck.

sclv
  • 38,665
  • 7
  • 99
  • 204
0

You can use permutations (in module Data.List) for this.

Here is the function signature for permutations:

permutations :: [a] -> [[a]]

As you can see, it returns a list of lists. Here is a little example (using GHCi 7.0.4):

> permutations [1..3]
[[1,2,3],[2,1,3],[3,2,1],[2,3,1],[3,1,2],[1,3,2]]

So you could do something like:

prop_unique_elements = forAll (elements (permutations [1..3])) $ \x -> foo == bar

I haven't tested that so it will need some massaging, but I hope it conveys the point clearly. Good luck.

Brandon
  • 1,956
  • 18
  • 18
  • I don't think forall does what you think it does. – sclv Sep 23 '11 at 19:15
  • @sclv What do I think it does? I always thought it was declaring universal quantification for the generator over the predicate. :) It obviously doesn't exhaustively run each permutation once, but each result from the generator will be a list with unique elements, as the questions asks. – Brandon Oct 17 '11 at 12:50
  • Then we just have different readings of the question -- I read it as asking for exhaustive testing -- i.e. picking a distinct element for each test, not as asking for a generator that produced lists of distinct elements for each test, but could potentially produce the same list on different tests. – sclv Oct 17 '11 at 13:31