GEq

Class of generic representation types that can be checked for equality.
A class for type-contexts which contain enough information to (at least in some cases) decide the equality of types occurring within them. This class is sometimes confused with TestEquality from base. TestEquality only checks type equality. Consider
>>> data Tag a where TagInt1 :: Tag Int; TagInt2 :: Tag Int
The correct TestEquality Tag instance is
>>> :{
instance TestEquality Tag where
testEquality TagInt1 TagInt1 = Just Refl
testEquality TagInt1 TagInt2 = Just Refl
testEquality TagInt2 TagInt1 = Just Refl
testEquality TagInt2 TagInt2 = Just Refl
:}
While we can define
instance GEq Tag where
geq = testEquality
this will mean we probably want to have
instance Eq Tag where
_ == _ = True
Note: In the future version of some package (to be released around GHC-9.6 / 9.8) the forall a. Eq (f a) constraint will be added as a constraint to GEq, with a law relating GEq and Eq:
geq x y = Just Refl   ⇒  x == y = True        ∀ (x :: f a) (y :: f b)
x == y                ≡  isJust (geq x y)     ∀ (x, y :: f a)
So, the more useful GEq Tag instance would differentiate between different constructors:
>>> :{
instance GEq Tag where
geq TagInt1 TagInt1 = Just Refl
geq TagInt1 TagInt2 = Nothing
geq TagInt2 TagInt1 = Nothing
geq TagInt2 TagInt2 = Just Refl
:}
which is consistent with a derived Eq instance for Tag
>>> deriving instance Eq (Tag a)
Note that even if a ~ b, the geq (x :: f a) (y :: f b) may be Nothing (when value terms are inequal). The consistency of GEq and Eq is easy to check by exhaustion:
>>> let checkFwdGEq :: (forall a. Eq (f a), GEq f) => f a -> f b -> Bool; checkFwdGEq x y = case geq x y of Just Refl -> x == y; Nothing -> True

>>> (checkFwdGEq TagInt1 TagInt1, checkFwdGEq TagInt1 TagInt2, checkFwdGEq TagInt2 TagInt1, checkFwdGEq TagInt2 TagInt2)
(True,True,True,True)
>>> let checkBwdGEq :: (Eq (f a), GEq f) => f a -> f a -> Bool; checkBwdGEq x y = if x == y then isJust (geq x y) else isNothing (geq x y)

>>> (checkBwdGEq TagInt1 TagInt1, checkBwdGEq TagInt1 TagInt2, checkBwdGEq TagInt2 TagInt1, checkBwdGEq TagInt2 TagInt2)
(True,True,True,True)
A class for type-contexts which contain enough information to (at least in some cases) decide the equality of types occurring within them.
Generic equality: an alternative to "deriving Eq"
Produce a witness of type-equality, if one exists. A handy idiom for using this would be to pattern-bind in the Maybe monad, eg.:
extract :: GEq tag => tag a -> DSum tag -> Maybe a
extract t1 (t2 :=> x) = do
Refl <- geq t1 t2
return x
Or in a list comprehension:
extractMany :: GEq tag => tag a -> [DSum tag] -> [a]
extractMany t1 things = [ x | (t2 :=> x) <- things, Refl <- maybeToList (geq t1 t2)]
(Making use of the DSum type from Data.Dependent.Sum in both examples)
Generic (==).
instance Eq MyType where
(==) = geq
A Predicate that accepts anything greater than or equal to the given value.
>>> accept (geq 5) 4
False

>>> accept (geq 5) 5
True

>>> accept (geq 5) 6
True
A pointer to an equality checking function on the C side.