I don’t know the original motivation, but I know plenty of cases when min
/ max
returning something different from their arguments is useful.
- Quite often the difference between semantical and structural equality is in some sort of annotation with a provenance / position. E. g.,
data Value = Value { getValue :: Int, getProvenance :: Position }
instance Eq Value where
(==) = (==) `on` getValue
Now what is the provenance of min x y :: Value
? It might be sensible to set Position
to <no location>
, or maybe to a position of min
itself, or maybe combine position ranges somehow. In all these cases min x y
is structurally neither x
nor y
(but semantically equal to one of them).
- Another case is that maybe
min
/max
does not evaluate anything, but just construct a correspondent expression. Say,
data Expr
= Const Int
| Add Expr Expr
| Mul Expr Expr
| Min Expr Expr
| Max Expr Expr
and then simply
min :: Expr -> Expr -> Expr
min = Min
- Further, if evaluation of
min
/max
requires some sort of normalisation of arguments, why would not we return the normalised value? For example, it makes a lot of sense formin (Add (Const 1) (Const 2)) (Const 5)
to returnConst 3
.
A variation of above is the following definition of min
for ByteString
:
min x y
| Data.ByteString.null x = mempty
| otherwise = ...
Even while x == mempty
, it is not necessarily structurally equal to it (it might be a zero slice of a larger ByteString
). And yet this is a sensible definition, useful to free up some over-retained data.