Есть ли способ контролировать, как GHC получает экземпляры `Eq`? - PullRequest
0 голосов
/ 30 октября 2018

Предположим, у меня есть простой перечислимый тип с 10 элементами:

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

GHC получает экземпляр Eq так, как вы ожидаете:

==================== 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

Однако, как только вы добавите 11-й конструктор K, GHC изменит способ получения экземпляра (якобы по соображениям эффективности):

==================== 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

Выпуск

Я использую инструмент, который использует исходный код на Haskell, и он может легко обрабатывать первые симпатичные экземпляры, но не последние некрасивые. Я надеюсь, что есть флаг, который заставляет GHC всегда создавать симпатичные экземпляры (даже если код, который на самом деле выполняется, тайно использует уродливые под капотом). В идеале мне не пришлось бы изменять исходный код (в противном случае я бы, вероятно, просто укусил бы пулю и сам написал бы красивые экземпляры).

Возможно ли это в настоящее время?

1 Ответ

0 голосов
/ 30 октября 2018

Если вы достаточно заботитесь об этом, вы можете написать себе какой-нибудь TH, чтобы сгенерировать «более симпатичные» Eq экземпляры. Вы можете черпать вдохновение из пакета deriving-compat Райана, который имеет deriveEq :: Name -> Q [Dec] (вы не можете использовать его напрямую, потому что Райан, как всегда, старался использовать точно такую ​​же специальную логику для типов данных с более 10 конструкторов).

Я надеюсь, что есть флаг, который заставляет GHC всегда создавать симпатичные экземпляры (даже если код, который на самом деле выполняется, тайно использует уродливые под капотом).

Нет. Похоже, 10 - это константа, жестко закодированная в том, как генерируется код для Eq ( source ).

...