ye9ane
ye9ane

Reputation: 2009

Access constructor name and arguments

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

Answers (1)

firefrorefiddle
firefrorefiddle

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

Related Questions