I am aware that the concept of invariants exists across multiple programming paradigms. For example, loop invariants are relevant in OO, functional and procedural programming.
However, one very useful kind found in OOP is an invariant of the data of a particular type. This is what I'm calling "type-based invariants" in the title. For example, a
Fraction type might have a
denominator, with the invariant that their gcd is always 1 (i.e. the fraction is in a reduced form). I can only guarantee this by having some kind of encapsulation of the type, not letting its data be set freely. In return, I never have to check whether it's reduced, so I can simplify algorithms like equality checks.
On the other hand, if I simply declare a
Fraction type without providing this guarantee through encapsulation, I can't safely write any functions on this type which assume that the fraction is reduced, because in the future somebody else could come along and add a way of getting hold of a non-reduced fraction.
Generally, the lack of this kind of invariant might lead to:
- More complex algorithms as pre-conditions need to be checked/ensured in multiple places
- DRY violations as these repeated pre-conditions represent the same underlying knowledge (that the invariant should be true)
- Having to enforce pre-conditions through runtime failures rather than compile-time guarantees
So my question is what the functional programming answer to this kind of invariant is. Is there a functional-idiomatic way of achieving more or less the same thing? Or is there some aspect of functional programming which makes the benefits less relevant?