An invariant is a condition or property that remains true for every valid state or execution covered by a specification. In functional design, finding a domain’s essence means finding its mathematical invariants and emphasizing them so correct behavior follows from them. section 1.3.3
For a pure algorithm, an invariant becomes a property that tests can challenge with generated inputs. This replaces an impractical collection of hand-written cases with checks over a broader class of values. section 15.1.2
Useful invariants expose both design structure and testing limits:
- A list-mapping operation preserves the input list’s length and internal structure while transforming element types; this behavior is generalized by the functor abstraction. section 1.3.3
- A property-based test generates values, checks the invariant, and shrinks failures toward a minimal counterexample. section 15.1.2
- Generated tests provide evidence rather than proof: an implementation can pass its tested range while failing on larger or unusual inputs. section 15.1.2
Testing a squaring invariant
The invariant for a squaring function is that, for every input x, the result equals x * x. A QuickCheck property can expose a malformed implementation quickly: malformedSquare returns incorrect results for most integers, and the test reports a falsifying input. A second implementation may still pass if generated values never exceed its hidden failure threshold, so the generation range must be considered when interpreting results. section 15.1.2
spec :: Spec spec = prop "square" $ #1 \x -> (malformedSquare x == x * x) #2 -- Test output: > Falsified (after 2 tests): 1
Inspect the property-based test and its falsifying output. section 15.1.2











