Testing equality between two heterogeneous values
-
13-07-2021 - |
سؤال
I'm using the -XExistentialQuantification
GHC extension to create a heterogeneous container for values of a specific type class (Shape
):
-- Container type
data Object = forall a. Shape a => Object a
-- 'Shape' class. Methods not important
class Eq s => Shape s where
doStuff :: s -> s
Given that all instances of Shape
are also instances of Eq
, is there a way to make Object
an instance of Eq
as well?
المحلول
It's possible if you add a Typeable
constraint:
import Data.Typeable
data Object = forall a. (Shape a, Typeable a) => Object a
instance Eq Object where
Object x == Object y =
case cast y of
Just y' -> x == y'
Nothing -> False
Here, cast y
will return Just y'
if the desired type of y'
(inferred from the use of ==
with x
) matches the actual type of y
, and Nothing
otherwise.
نصائح أخرى
No, because Eq a
says you can compare two values of type a
. An Eq
instance on your object would allow arbitrary pairs of values (of any type that is an instance of Shape
) to be compared.
If I have Shape Int
and Shape Bool
instances, how can I compare Object True
with Object 1
for equality?
A value of a type which implements Eq
can only be compared with another value of the same type - not of any other type that implements Eq
. So if you have two values of different types, you can't compare them even if they're both instances of Shape
(and thus Eq
). Therefore it's also impossible to have an Eq
instance for Object
as an Object
can contain values of different types - at least using the types' Eq instances.
What you'd need would be a function of type (Shape a, Shape b) => a -> b -> Bool
that can be used to compare any shape to any other shape. If you have such a function, you can use that to create an Eq
instance for Object
. However you won't be able to define such a function in a way that's consistent with the types' Eq
instances.