A pseudo-random number generator computes a value from a state, then returns an updated state. Passing that new state into the next call produces a sequence while keeping the computation pure: the same input state gives the same result. section 9.1.2
Listing 9.2 Functions to explicitly work with random state
newtype RandomState = RandomState Int
deriving (Eq, Show) #1
randomInt :: RandomState -> (Int, RandomState)
randomInt (RandomState rs) = (newRs, RandomState newRs) #2
where
newRs = (1103515245 * rs + 12345) `mod` (2 ^ 31) #3
randomIntList :: RandomState -> Int -> [Int]
randomIntList rs n
| n <= 0 = [] #4
| otherwise =
let (v, rs') = randomInt rs #4
in v : randomIntList rs' (n - 1) #4
This explicit generator threads `RandomState` through each call. `randomInt` applies a linear congruential transformation; `randomIntList` feeds the returned state back recursively to build integer values. section 9.1.2
For ordinary programs, `System.Random` supplies generation functions for multiple types instead of requiring a custom numeric generator. Pure code carries generator state through arguments and results; IO actions can access a global generator. section 9.1.2 section 9.6
Random generators become most useful in property testing when they can create inputs that fit the property:
- Generate many lists to check that a sorting function returns sorted output, reporting the input when a test fails. section 9.1.5
- Compose generators rather than writing an unrelated generator for every data type or input condition. section 9.1.5
- Restrict generated values when a property has preconditions, such as requiring a nonempty alphabet containing the tested character. section 9.3.1
- Use QuickCheck’s type-driven generators; `Arbitrary` also supports shrinking failures to smaller or simpler values. section 9.6
Testing a rotation property
A property for alphabet rotation expects the rotated character to remain in its alphabet. Unconstrained generation quickly finds that an empty alphabet violates this expectation, revealing that valid test data must satisfy the property’s assumptions. section 9.3.1
For referentially transparent functions, random inputs need no simulated external environment: correctness can be checked by comparing input-derived outputs against a predicate. Generator choice and property interpretation determine whether such a test is valid. section 9.2.1









