Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell - simple constructor comparison (?) function

Tags:

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 ;)

like image 804
nietaki Avatar asked Apr 11 '12 19:04

nietaki


People also ask

Can you compare functions in Haskell?

Most notably, in Haskell, functions are not in the Eq typeclass (in general). Not any two functions can be compared for equality in Haskell.

What are type constructors in Haskell?

Type constructorOf any specific type a , be it Integer , Maybe String , or even Tree b , in which case it will be a tree of tree of b . The data type is polymorphic (and a is a type variable that is to be substituted by a specific type). So when used, the values will have types like Tree Int or Tree (Tree Boolean) .

What does () mean in Haskell?

() is very often used as the result of something that has no interesting result. For example, an IO action that is supposed to perform some I/O and terminate without producing a result will typically have type IO () .

What is constructor data type?

A data constructor is a "function" that takes 0 or more values and gives you back a new value. A type constructor is a "function" that takes 0 or more types and gives you back a new type.


1 Answers

Take a look at Data.Data and its toConstr function. 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 a Data instance derived for you automatically:

data PhpValue = VoidValue | IntValue Integer | BoolValue Bool                deriving (Typeable, Data) 

You should then be able to use the toConstr function to compare by constructor.

Now the following will be true:

toConstr (BoolValue True) == toConstr (BoolValue False) 

Using on from Data.Function you can now rewrite sameConstructor to:

sameConstructor = (==) `on` toConstr 

This is the same as

sameConstructor l r = toConstr l == toConstr r 

I think the version using on is easier to read at a glance.

like image 171
Tikhon Jelvis Avatar answered Sep 29 '22 12:09

Tikhon Jelvis