In my project I have created a data type, that can hold one of a few types of values:
data PhpValue = VoidValue | IntValue Integer | BoolValue Bool
What I wanted to do now, is to have a simple way of checking if two values of the PhpValue type are of the same constructor (correct me if I’m confused with the terminology here, but basically what I want to check if both are, for example, are IntValue, without caring about the particular value).
Here is a function I wrote for that:
sameConstructor :: PhpValue -> PhpValue -> Bool
sameConstructor VoidValue VoidValue = True
sameConstructor (IntValue _) (IntValue _) = True
sameConstructor (BoolValue _) (BoolValue _) = True
sameConstructor _ _ = False
This works as it should, but I don’t really like it: if I add more constructors (like FloatValue Float) I am going to have to rewrite the function, and it will get bigger as my data definition gets bigger.
The Question: Is there a way of writing such a function, so that its implementation doesn’t change when I add more constructors?
For the record: I don’t want to change the data definition, I have enough Monads in the rest of my code as it is 😉
Take a look at
Data.Dataand itstoConstrfunction. This returns a representation of the constructor which can be compared for equality.With an extension (you can put
{-# LANGUAGE DeriveDataTypeable #-}at the top of your module), you can have aDatainstance derived for you automatically:You should then be able to use the
toConstrfunction to compare by constructor.Now the following will be true:
Using
onfromData.Functionyou can now rewritesameConstructorto:This is the same as
I think the version using
onis easier to read at a glance.