Reputation: 2009
I'm going to override the equal class for Dynamic data type in this way:
instance Eq Dynamic where
x==y = dynamicEq x y
dynamicEq :: Dynamic -> Dynamic -> Bool
dynamicEq x y = ConstrName x == ConstrName y && sameSlots(slots x)(slots y)
where
sameSlots [] [] = True
sameSlots ((x::Eq a => a):xs)(y:ys) = x == fromDynamic y && sameSlots xs ys
can you name or declare any function that can return the values of ConstrName and slots for me? Maybe using Tycon or something similar?
Upvotes: 0
Views: 209
Reputation: 3805
Never fiddled with this stuff, but here may be two partial answers which could be enough for you. I'm afraid it's not a general solution nor a way to make Dynamic
and instance of Eq
(it would probably be one already if it was easy).
But in your last comment you stated that you only wanted to compare your own types. So, partial answer 1:
You can of course compare two Dynamics
if you guess their type. For example:
eqInt :: Int -> Int -> Bool
eqInt = (==)
x = toDyn (3::Int)
y = toDyn (3::Int)
z = toDyn (4::Int)
compareDynamic :: (Typeable a, Eq a) =>
(a -> a -> Bool) ->
Dynamic -> Dynamic -> Maybe Bool
compareDynamic eq x y = do
let dEq = toDyn eq
fn1 <- dynApply dEq x
res <- dynApply fn1 y
fromDynamic res
And now:
...> compareDynamic eqInt x y
Just True
...> compareDynamic eqInt x z
Just False
However, despite the misleading polymorphic type of compareDynamic
, you can only pass in a monomorphic comparison function. See:
...> compareDynamic (==) x z
Nothing
I suppose that is because the type system has no way of knowing which instance of (==)
it should actually use here. I kept compareDynamic
polymorphic though so you don't have to create separate functions for each type.
Now, since you only want to compare your own types, you could just have a list of comparison functions which you try in order:
eqs = [eqMyTypeA, eqMyTypeB, eqMyTypeC]
comp dynA dynB = catMaybes $ map (\eq -> eq dynA dynB) eqs
And []
would denote two different types, [Just False]
the same type with different values and [Just True]
the same type and value.
In case you have a large number of types, you can also determine the constructor before doing any comparison, (this is partial answer 2) and select the right function depending on it. It the constructors are different, you wouldn't have to try compare at all:
constructor :: Dynamic -> TyCon
constructor = typeRepTyCon . dynTypeRep
And have a lookup table matching constructors to equality functions.
One closing remark: Think twice if you need this. Think thrice if you need Dynamic
at all, most Haskell programs don't. Isn't it just Java thinking sneaking in?
Upvotes: 1