Reputation: 2918
I need to derive Eq for a data, but for some constructors I want to ignore some fields. The data is for representing DataTypes (we are developing a compiler):
data DataType
= Int | Float | Bool | Char | Range | Type
| String Width
| Record (Lexeme Identifier) (Seq Field) Width
| Union (Lexeme Identifier) (Seq Field) Width
| Array (Lexeme DataType) (Lexeme Expression) Width
| UserDef (Lexeme Identifier)
| Void | TypeError
deriving (Ord)
I need to ignore the Width
field from every contstructor it appears in.
Upvotes: 2
Views: 420
Reputation: 137977
You cannot derive Eq if you wish to use custom Eq semantics. You must write an instance by hand.
A common trick is to:
a == b = toDataType' a == toDataType' b
This at least makes it less ad hoc, capturing the different Eq semantics in its own type, where it /can/ be derived.
Upvotes: 8
Reputation: 1803
You could write your own instance of Eq
:
instance Eq DataType where
Int == Int = True
Float == Float = True
Bool == Bool = True
Char == Char = True
Range == Range = True
Type == Type = True
(String _) == (String _) = True
(Record l1 s1 _) == (Record l2 s2 _) = (l1 == l2) && (s1 == s2)
(Union l1 s1 _) == (Union l2 s2 _) = (l1 == l2) && (s1 == s2)
(Array l1 e1 _) == (Array l1 e1 _) = (l1 == l2) && (e1 == e2)
(UserDef i1) == (UserDef i2) = i1 == i2
Void == Void = True
TypeError == TypeError = True
_ == _ = False
Upvotes: 1
Reputation: 1667
Another approach from Don's is to use a wrapper type to encode the instances you want for the special fields:
newtype Metadata a = Metadata { unMetadata :: a }
instance Eq (Metadata a) where
(==) _ _ = True
instance Ord (Metadata a) where
compare _ _ = EQ
You can then replace all the Width
's in your DataType definition with Metadata Width
and derive the instances.
data DataType
= Int | Float | Bool | Char | Range | Type
| String (Metadata Width)
| Record (Lexeme Identifier) (Seq Field) (Metadata Width)
| Union (Lexeme Identifier) (Seq Field) (Metadata Width)
| Array (Lexeme DataType) (Lexeme Expression) (Metadata Width)
| UserDef (Lexeme Identifier)
| Void | TypeError
deriving (Eq, Ord)
This solution makes your DataType definition a bit more verbose (and more explicit?) but requires wrapping and unwrapping when using the Width
values.
Upvotes: 7