liveBook · Manning

Shrink

As explained in Learn Haskell by Example

shrink is the QuickCheck type-class method that produces smaller candidate values to simplify a failing test case.

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

How Learn Haskell by Example covers it

How deep it goes
Defines the pure shrinking contract, iteration, termination concern, and invariant-preserving custom implementation.
Examples
Uses character candidates and an invariant-preserving shrinkAssocMap implementation for associative maps.
What it assumes
Assumes property testing and Arbitrary instances while treating random generation as the surrounding context.
What you can do after
Diagnose/debug with it by producing smaller, deterministic counterexamples for custom Arbitrary instances.
How it connects
Connects Arbitrary, QuickCheck, property testing, random generation, and data invariants.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Learn Haskell by Example. The section links point to the parts of the book it draws on.