shrink is the Arbitrary type-class method QuickCheck uses to simplify a failing property-test input. Its type, a -> [a], makes it a pure, deterministic function that returns candidate replacements rather than generating random values. section 9.4.3 section 9.4
QuickCheck repeatedly applies shrinking and rechecks the property:
- Find an input that falsifies the property. section 9.4.3
- Try the values returned by shrink. section 9.4.3
- Keep simplifying while a smaller value remains a counterexample. section 9.4.3
- Do not return the original input, or shrinking can loop forever. section 9.4.3
Shrinking an associative map
For newtype AssocMap k v = AssocMap [(k, v)], shrink the underlying list and rebuild each result, removing duplicate keys with nubBy. This preserves the map invariant while allowing QuickCheck to try smaller maps and shorter contents. An Arbitrary instance connects the custom function with shrink = shrinkAssocMap. section 9.4.2 section 9.4.3
Listing 9.21 A shrink function for associative maps
shrinkAssocMap :: #1
(Eq k, Arbitrary k, Arbitrary v) => #1
AssocMap k v -> #1
[AssocMap k v] #1
shrinkAssocMap (AssocMap xs) = #1
L.map #1
(AssocMap . L.nubBy (\(k1, _) (k2, _) -> k1 == k2)) #1
(shrink xs) #2
The implementation shows how list shrinking can be adapted for a structured type without losing unique-key invariants. section 9.4.3
