0

I expect the below code to produce a generator of lists of a of size 1, 2 or 3, with each element generated independently.

shortlist :: Arbitrary a => Gen [a]
shortlist = oneof $ map promote [[arbitrary],  
                                 [arbitrary, arbitrary], 
                                 [arbitrary, arbitrary, arbitrary]]

REPL:

sample (shortlist :: Gen [Char])
"\255\255\255"
"ii"
"FF"
"\236\236"
"FF"
"'''"
"8"
"HH"
"\160"
"\DEL\DEL\DEL"
"\246\246" 

Each list contains 1, 2 or 3 instances of the same char. Why is arbitrary not behaving as expected?

pkinsky
  • 1,718
  • 2
  • 23
  • 28
  • 1
    the answers are rather good I think - maybe someone wants a direct link to the source for promote: http://hackage.haskell.org/package/QuickCheck-2.7.6/docs/src/Test-QuickCheck-Gen-Unsafe.html#promote - I think it's rather clear from there what's happening – Random Dev Aug 14 '14 at 06:01
  • Thanks, I'll make sure to RTFM first next time. It's disappointing that the standard 'Just inspect the Type' Haskell advice isn't applicable, though. – pkinsky Aug 14 '14 at 14:32

2 Answers2

6

I really had to look for promote. The module description says that the functions provided in that module will reuse random number seeds. Instead of using promote, you should use something like replicateM or sequence.

For example:

shortlist :: Arbitrary a => Gen [a]
shortlist = oneof $ map sequence [[arbitrary],  
                                  [arbitrary, arbitrary], 
                                  [arbitrary, arbitrary, arbitrary]]

or

shortlist :: Arbitrary a => Gen [a]
shortlist = oneof $ [ replicateM n arbitrary | n <- [1..3] ]

will yield something like:

> sample (shortlist :: Gen [Char])
"\SI"
"aP"
"\153\US\STX"
"#k"
"U"
"}\DC1"
"i"
"\186F"
"\148k"
"\RS|\159"
"\192L"
Carl
  • 26,500
  • 4
  • 65
  • 86
  • 2
    may I suggest rewriting the first paragraph? It sounds a bit rude ("if you actually bothered ...") - I thinks this could be much better with a bit more of a friendlier wording ;) – Random Dev Aug 14 '14 at 06:19
6

In QuickCheck-2.7.6. promote has been moved to the Test.QuickCheck.Gen.Unsafe module.

The comments there explain what you are seeing:

Gen is only morally a monad: two generators that are supposed to be equal will give the same probability distribution, but they might be different as functions from random number seeds to values. QuickCheck maintains the illusion that a Gen is a probability distribution and does not allow you to distinguish two generators that have the same distribution.

The functions in this module allow you to break this illusion by reusing the same random number seed twice. This is unsafe because by applying the same seed to two morally equal generators, you can see whether they are really equal or not.

ErikR
  • 51,541
  • 9
  • 73
  • 124