There's no straightforward way to incorporate the default Eq A instance generated by GHC into your own Eq A instance. The problem is that generation of the code for the instances is tied to the process of defining those instances -- the only way to generate the default Eq A code is to actually generate the unique Eq A instance, and once the instance is generated, you can't really change it. I don't see any way, even with GHC "deriving"-related extensions, of working around this problem.
However, there's a reimplementation of the default Eq instance provided by the package generic-deriving which you could use. With some preamble:
{-# LANGUAGE DeriveGeneric #-}
import GHC.Generics
import Generics.Deriving.Eq -- from package generic-deriving
define your data type with a derived Generic instance:
data A
= B Int
| C Float
| D A
deriving (Generic)
Then, define a GEq instance that implements your special case for the D constructor while deferring to the default implementation for the rest.
instance GEq A where
D _ `geq` D _ = True
x `geq` y = x `geqdefault` y
Finally, define an Eq instance the uses this generic equality class.
instance Eq A where
(==) = geq
After that, it should all work as expected:
> D (B 10) == D (B 20)
True
> B 10 == B 20
False
>
However, it might be more reasonable to take the advice in the comments, and either:
Do what @malloy suggests. The operation you're trying to define isn't really (==), so why do need to name it (==)? Just derive the usual Eq instance and write a separate function to avoid the unwanted recursion:
equalClasses :: A -> A -> Bool
equalClasses (D _) (D _) = True
equalClasses x y = x == y
If you really want to use a (==), I think using a newtype as suggested by @luqui is probably the most idiomatic approach:
data A'
= B Int
| C Float
| D A'
deriving (Eq)
newtype A = A A'
instance Eq A where
A (D _) == A (D _) = True
A x == A y = x == y
(==).Eqinstance - and I don't see your example as being fundamentally different.