There are times when values need to be tested for equality or compared for ordering, even if they aren't statically known to be of equivalent types. Such a test, if successful, may allow that knowledge to be recovered.
base (on singletons):
-
TestCoercion f
$\approx$ (HetEq f, Strength f ~ Representational)
-
TestEquality f
$\approx$ (HetEq f, Strength f ~ Nominal)
some (universally):
-
GEq f
$\cong$ (HetEq f, Strength f ~ Nominal)
-
GCompare f
$\cong$ (HetOrd f, Strength f ~ Nominal)
HetEq
and HetOrd
are generalised over the strength of evidence captured.
This allows them to admit and combine a much broader range of instances, e.g.
instance Eq a => HetEq (Const a) where
type Strength (Const a) = Phantom
...
instance HetEq IORef where
type Strength IORef = Representational
...
instance HetEq TypeRep where
type Strength TypeRep = Nominal
...
type HetEq' f = (KnownRole (Strength f), HetEq f)
instance (HetEq' f, HetEq' g) => HetEq (Product f g) where
type Strength (Product f g) = Max (Strength f) (Strength g)
...
instance (HetEq' f, HetEq' g) => HetEq (Sum f g) where
type Strength (Sum f g) = Min (Strength f) (Strength g)
...
Consequently, Data.Hetero.Some
has much broader Eq
and Ord
instances than Data.Some
:
instance HetEq f => Eq (Some f)
instance HetOrd f => Ord (Some f)
dependent-map could similarly broaden the range of key types by replacing GCompare k
with (HetOrd k, Strength k > Phantom)
, though the rare operations requiring Has' _ k f
constraints might not come out on top.