1
votes

Suppose I have a simple enumerated type with 10 elements:

data Test = A | B  | C | D | E | F | G | H | I | J
  deriving Eq

GHC derives the Eq instance as you'd expect:

==================== Derived instances ====================
Derived class instances:
  instance GHC.Classes.Eq Test.Test where
    (GHC.Classes.==) (Test.A) (Test.A) = GHC.Types.True
    (GHC.Classes.==) (Test.B) (Test.B) = GHC.Types.True
    (GHC.Classes.==) (Test.C) (Test.C) = GHC.Types.True
    (GHC.Classes.==) (Test.D) (Test.D) = GHC.Types.True
    (GHC.Classes.==) (Test.E) (Test.E) = GHC.Types.True
    (GHC.Classes.==) (Test.F) (Test.F) = GHC.Types.True
    (GHC.Classes.==) (Test.G) (Test.G) = GHC.Types.True
    (GHC.Classes.==) (Test.H) (Test.H) = GHC.Types.True
    (GHC.Classes.==) (Test.I) (Test.I) = GHC.Types.True
    (GHC.Classes.==) (Test.J) (Test.J) = GHC.Types.True
    (GHC.Classes.==) _ _ = GHC.Types.False

However, once you add an 11th constructor K, GHC changes the way the instance is derived (ostensibly for efficiency reasons):

==================== Derived instances ====================
Derived class instances:
  instance GHC.Classes.Eq Test.Test where
    (GHC.Classes.==) a_a1uD b_a1uE
      = case (Test.$con2tag_7MvV0ZqFtYZ8X4oGLC1npJ a_a1uD) of {
          a#_a1uF
            -> case (Test.$con2tag_7MvV0ZqFtYZ8X4oGLC1npJ b_a1uE) of {
                 b#_a1uG -> (GHC.Prim.tagToEnum# (a#_a1uF GHC.Prim.==# b#_a1uG)) } }

  Test.$con2tag_7MvV0ZqFtYZ8X4oGLC1npJ :: Test.Test -> GHC.Prim.Int#
  Test.$con2tag_7MvV0ZqFtYZ8X4oGLC1npJ a_a1uC
    = GHC.Base.getTag a_a1uC

The issue

I'm using a tool that consumes Haskell source code and it can easily handle the former pretty-looking instances but not the latter ugly ones. What I'm hoping is that there is a flag that forces GHC to always produce the pretty instances (even if the code that is actually run is secretly using the ugly ones under the hood). Ideally, I would not have to modify the source code (otherwise, I'd probably just bite the bullet and hand-write the pretty instances myself).

Is this currently possible?

1
The would make a very good GHC feature request. There's no inherent reason not to let the threshold be changed by a compiler flag. The main goal of this strategy is to deal with Ord instances, since those have N^2 cases for N constructors. I'm not really sure why this is used for Eq, but it might be to let the optimizer be a bit more clever when Eq and Ord code are used together.dfeuer

1 Answers

5
votes

If you care enough about this, you could write yourself some TH to generate the "prettier" Eq instances. You can take inspiration from Ryan's deriving-compat package, which has deriveEq :: Name -> Q [Dec] (you can't use it directly because Ryan, thorough as ever, made sure to port over exactly the same special logic for datatypes with more than 10 constructors).

What I'm hoping is that there is a flag that forces GHC to always produce the pretty instances (even if the code that is actually run is secretly using the ugly ones under the hood).

No. Looks like 10 is a constant hardcoded into how the code for Eq is generated (source).