Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

(Re)-defining (==) for class Eq

Tags:

haskell

In the following example:

data ColourName 
  = White
  | Grey
  | Gray
  | Black
  | Blue
  -- ...
  -- hundreds more of colours
  -- ...
  | LastColor
  deriving (Read, Show, Eq)

I'd like to redefine (==) so that Grey and Gray evaluate as equal.

Obviously, one way would be to not include Eq in deriving, however, then I'd have to define

(==) :: ColourName
(==) White White = True
(==) Gray Gray = True
(==) Grey Grey = True
(==) Gray Grey = True
(==) Grey Gray = True
(==) Black Black = True
-- frickin' log of other colors, hundreds of lines of typing
(==) LastColor LastColor = True
(==) a b = False

which is nothing I plan to do.

I also can't do

instance Eq ColourName where
    (==) :: ColourName -> ColourName -> Bool
    (==) Gray Grey = True
    (==) Grey Gray = True
    (==) a b = (a == b)

because this leads to an infinite recursion, is basically underdefined.

Is there a way out?

(No, I don't want to use data Colour = Colour String or similar. I want the valid colours to be represented as an enumeration, such providing automatic validation, but want to allow spelling variation for the end users of the module!)

like image 582
A Sz Avatar asked Nov 28 '22 00:11

A Sz


2 Answers

You can use the derived Enum instance :

data ColourName = Gray | Grey | ...
  deriving (Read, Show, Enum)

instance Eq ColourName where
  Gray == Grey = True
  Grey == Gray = True
  a == b = fromEnum a == fromEnum b

Edit: You can also use PatternSynonyms with GHC 7.8+. It works like a smart constructor, but can also be used in pattern matches.

pattern Gray = Grey
like image 104
Piezoid Avatar answered Dec 28 '22 23:12

Piezoid


Do not do this. It won't work well with pattern matching. It will break something like

f Gray = g
f x    = h

because pattern matching does not care about your Eq instance.

By break, I mean it won't have the behavior you want, since f Grey would end up calling h rather than g, even though you would expect for f x == f y for all x == y. This means the programmer has to explicitly remember to make cases for both f Gray and f Grey which is just dumb.

If you are determined to have an ugly hack to allow for alternate spellings, I suppose you can do

#define Gray Grey

with CPP enabled.

like image 25
alternative Avatar answered Dec 28 '22 23:12

alternative