Suppose I have defined some data type that derives Eq but want to insert my own definition of (==) for some pattern. Is there any way to do this or do I have to define (==) for every pattern?
e.g.
data Asdf = One Char | Two Char Char --(deriving Eq)
instance Eq Asdf where
(==) (One _) (One _) = True
--otherwise use what the derived definition would have done
--can I do this without defining these patterns myself?
To do what you're trying to do, you have to define it yourself, and that means you have to define it for every pattern.
Basically data MyType x = A x | B x x deriving (Eq)
will add a default derivation equivalent to,
instance Eq x => Eq (MyType x) where
A x1 == A x2 = x1 == x2
B x1 x2 == B x3 x4 = x1 == x3 && x2 == x4
_ == _ = False
Note that it figures out the necessary dependencies (the Eq x =>
part above) as well as fills in the diagonal cases -- the special cases among the n2 possible matches where the same constructor was used.
As far as I know, it does this definition all-at-once and there is no way to dig into an existing instance declaration to mess with it -- and there is a good reason for this; if they let you do this then that would mean that as codebases grow, you could not look at an instance derivation or a deriving (Eq)
clause and be confident that you know exactly what it means, since some other part of the code might monkey-patch that Eq
instance to do something nefarious.
So one way is to redefine the diagonal yourself. But that's not the only way. There is at least one alternative which may work if it's easier to modify several usage sites than to shove all n constructors into a single thing:
newtype EverythingIsEqual x = E x deriving (Show)
instance Eq (EverythingIsEqual x) where
_ == _ = True
data MyType x = A (EverythingIsEqual x) | B x x deriving (Show, Eq, Ord)
This newtype
allows you to strategically modify certain terms to have a different Eq
relation at no runtime cost -- in fact this is pretty much one of the two central arguments for newtypes; aside from the lesser one where "I want to have a type-level difference between these two Strings but they ARE just strings and I don't want to pay any performance penalty," there is the greater argument of "sometimes we want to tell Haskell to use a different Ord
dictionary without messing with any of the values that this dictionary acts upon, we just want to swap out the functions."
This question discusses how to do something very similar for the Show
instance, using the https://hackage.haskell.org/package/generic-deriving package: Accessing the "default show" in Haskell?
See this answer in particular: https://stackoverflow.com/a/35385768/936310
I recently used it for the Show
instance recently, and it worked wonderfully. You can similarly derive Eq
as well for your type, assuming it's regular enough.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With