I see a discussion of how the one-sided clamps can be implemented only for floating-point using NaN, but my concern is the API for Ord types generally. ‘clamp (lo, hi) x = min hi (max x lo)’ allows ‘atLeast lo = clamp (lo, 0/0)’ and ‘atMost hi = clamp (0/0, hi)’, which is excellent for providing reasonable NaN handling, but doesn’t say anything about e.g. integers. It does point to the fact that the correct implementations of ‘atLeast’ and ‘atMost’, for consistency with the correct ‘clamp’ for floats, are actually these:
atMost = min
atLeast = flip max -- rather than just ‘max’
To me, that’s another argument that these should be considered, since it’s the kind of subtle distinction that libraries should be handling for users, along the same lines as the stability of ‘min’ & ‘max’ (namely: ‘a == b ==> (min a b, max a b) == (a, b)’). Again, this doesn’t necessarily need to go in the same MR, but they are closely related.
If they were included, it would be necessary to include a note in the documentation that the correct order is ‘atMost hi . atLeast lo’ if someone is applying them separately, but that ‘clamp’ should be preferred for automatically doing this.
I don’t know offhand how this would be disrupted down the line if we changed the ‘Ord’ instance for floats to use the IEEE-754 total ordering, but that should also be considered for all these functions.