Gen
and MonadGen
How QuickCheck Generates Random Data
So, how does QuickCheck generate random data? Essentially, it uses a linear congruential generator to produce random numbers. Values can be created based on that number. Let's give some examples.
Let's say the randomly generated number is x
where x
is a Number
:
- Primitives:
- Boolean: if
0 < x
andx < 0.5
, we might produce atrue
value andfalse
otherwise. - Int: we can convert
x
to anInt
viaceil
- Char: we can map
x
to anInt
and then produce a corresponding Unicode value viatoCharCode
. - String: by generating numerous
Char
values, we can combine them together into aString
value.
- Boolean: if
- Containers:
- Maybe: given a
Gen a
, we can generateNothing
if0 < x && x < 0.5
andJust a
otherwise. - Either: given a
Gen a
and aGen b
, we can generateLeft a
if0 < x && x < 0.5
andRight b
otherwise. - List: given a
Gen a
and anInt
indicating the number of values to generate, we can use the first generator to produce ana
value and cons that ontoNil
or the rest of the list. - Array: we can generate a
List a
and then usefromUnfoldable
- Maybe: given a
The Gen
Monad and its MonadGen
Type Class
In purescript-gen
, MonadGen is the type class that has a default implementation via Gen. To see all of the definitions of the types used in Gen
, look below:
-- This Int will always be between 1 and 2147483647,
-- which is (2^31 - 1), a Mersenne prime.
-- It is used in a linear congruential generator.
newtype Seed = Seed Int -- This will always be a positive integer
type Size = Int
type GenState = { newSeed :: Seed, size :: Size }
newtype Gen a = State GenState a
QuickCheck uses the Gen
monad (i.e. generator monad) to generate random data. QuickCheck.Gen
exports most of the package's functions (i.e. the "combinators" as they are called), not but all of them.
- Generators for
Int
,Boolean
, andNumber
. - Generators for common FP container types, such as
Maybe
,Either
,Tuple
, etc.
Furthermore, some data types combinators exist in other libraries. For example:
The Importance of the Seed
Value
The Seed
value is used to produce the random data. If you run a propety test and it fails, the failure message will also include the seed used to produce that data. Once you update your code to fix the bug, how would you know whether it fixed that particular instance? You would run the test and specify that it should use that specific seed.
As an example, this repository includes some example programs in the Projects
folder. One of my property tests failed, so I saved the seeds here: https://github.com/JordanMartinez/purescript-jordans-reference/issues/351.
I can use those seeds to help troubleshoot why these problems occurred and ensure that the bug has indeed been fixed.