This is a followup question to Inconsistent Eq and Ord instances?.
The question there is essentially: when declaring Eq
and Ord
instances for a type, must one ensure that compare x y
returns EQ
if and only if x == y
returns True
? Is it dangerous to create instances that break this assumption? It seems like a natural law one might assume, but it doesn’t appear to be explicitly stated in the Prelude, unlike e.g. the monad or functor laws.
The basic response was: it is a bit dangerous to do this, since libraries may assume that this law holds.
My question, now, is: do any of the standard libraries (in particular, Set
or Map
) make this assumption? Is it dangerous to have a type with incompatible Eq
and Ord
, so long as I am only relying on the standard libraries supplied with GHC? (If big-list questions were still acceptable, I would be asking: which commonly used libraries assume this law?)
Edit. My use-case is similar to that of the original question. I have a type with a custom instance of Eq
, that I use quite a bit. The only reason I want Ord
is so that I can use it as the domain of a Map
; I don’t care about the specific order, and will never use it explicitly in code. So if I can use the derived instance of Ord
, then my life will be easier and my code clearer.
The definition of Ord
itself in the standard prelude requires there already be an Eq
instance:
class (Eq a) => Ord a where
...
So it would be just as wrong to violate
x == y = compare x y == EQ
x /= y = compare x y /= EQ
As it would be to violate (from the default definitions for these operators in Ord).
x <= y = compare x y /= GT
x < y = compare x y == LT
x >= y = compare x y /= LT
x > y = compare x y == GT
Edit: Use in libraries
I would be quite surprised if standard libraries didn't make use of Ord
's ==
and /=
operators. The specific purpose operators (==
, /=
, <=
, <
, >=
, >
) are frequently more convenient than compare
, so I'd expect to see them used in code for map
s or filter
s.
You can see ==
being used in guards on keys in Data.Map
in fromAscListWithKey. This specific function only calls out for the Eq
class, but if the key is also an Ord
instance, Ord
's compare
will be used for other functions of the resulting Map
, which is an assumption that Eq
's ==
is the same as Ord
's compare
and testing for EQ
.
As a library programmer, I wouldn't be surprised if any of the special purpose operators outperformed compare
for the specific purpose. After all, that's why they are part of the Eq
and Ord
classes instead of being defined as polymorphic for all Eq
or Ord
instances. I might make a point of using them even when compare
is more convenient. If I did, I'd probably define something like:
compareOp :: (Ord a) => Ordering -> Bool -> a -> a -> Bool
compareOp EQ True = (==)
compareOp EQ False = (/=)
compareOp LT True = (<)
compareOp LT False = (>=)
compareOp GT True = (>)
compareOp GT False = (<=)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With