Получение ассоциированных синонимов типов с шаблоном Haskell

257

Может ли Template Haskell узнать имена и / или объявления синонимов связанных типов, объявленных в классе типов? Я ожидал, reifyчто сделаю то, что хочу, но, похоже, он не предоставляет всей необходимой информации. Он работает для получения сигнатур типов функций:

% ghci
GHCi, version 7.8.3: http://www.haskell.org/ghc/  :? for help
...
Prelude> -- I'll be inserting line breaks and whitespace for clarity
Prelude> -- in all GHCi output.
Prelude> :set -XTemplateHaskell 
Prelude> import Language.Haskell.TH
Prelude Language.Haskell.TH> class C a where f :: a -> Int
Prelude Language.Haskell.TH> putStrLn $(stringE . show =<< reify ''C)
ClassI (ClassD [] Ghci1.C [PlainTV a_1627398388] []
               [SigD Ghci1.f
                     (ForallT [PlainTV a_1627398388]
                              [ClassP Ghci1.C [VarT a_1627398388]]
                              (AppT (AppT ArrowT (VarT a_1627398388))
                                    (ConT GHC.Types.Int)))])
       []

Однако добавление синонима ассоциированного типа к классу не вызывает изменений (вплоть до переименования) в выходных данных:

Prelude Language.Haskell.TH> :set -XTypeFamilies 
Prelude Language.Haskell.TH> class C' a where type F a :: * ; f' :: a -> Int
Prelude Language.Haskell.TH> putStrLn $(stringE . show =<< reify ''C')
ClassI (ClassD [] Ghci3.C' [PlainTV a_1627405973] []
               [SigD Ghci3.f'
                     (ForallT [PlainTV a_1627405973]
                              [ClassP Ghci3.C' [VarT a_1627405973]]
                              (AppT (AppT ArrowT (VarT a_1627405973))
                                    (ConT GHC.Types.Int)))])
       []

Если я знаю имя F, я могу посмотреть информацию о нем:

Prelude Language.Haskell.TH> putStrLn $(stringE . show =<< reify ''F)
FamilyI (FamilyD TypeFam
                 Ghci3.F
                 [PlainTV a_1627405973]
                 (Just StarT))
        []

Но я не могу найти имя Fв первую очередь. Даже если я добавлю экземпляр класса типа, у InstanceDнего нет информации об определении:

Prelude Language.Haskell.TH> instance C' [a] where type F [a] = a ; f' = length
Prelude Language.Haskell.TH> f' "Haskell"
7
Prelude Language.Haskell.TH> 42 :: F [Integer]
42
Prelude Language.Haskell.TH> putStrLn $(stringE . show =<< reify ''C')
ClassI (ClassD [] Ghci3.C' [PlainTV a_1627405973] []
               [SigD Ghci3.f'
                     (ForallT [PlainTV a_1627405973]
                              [ClassP Ghci3.C' [VarT a_1627405973]]
                              (AppT (AppT ArrowT (VarT a_1627405973))
                                    (ConT GHC.Types.Int)))])
       [InstanceD []
                  (AppT (ConT Ghci3.C')
                        (AppT ListT (VarT a_1627406161)))
                  []]

Если reifyне сработает, есть ли обходной путь, кроме перечисления синонимов ассоциированного типа вручную?

Эта проблема присутствует в GHC 7.8.3 с версией 2.9.0.0 пакета template-haskell; он также присутствовал в GHC 7.4.2 с версией 2.7.0.0 пакета template-haskell. (Я не проверял GHC 7.6. *, Но я думаю, что он там тоже присутствовал.) Мне интересны решения для любой версии GHC (включая «это было исправлено только в GHC версии V »).

Антал Спектор-Забуский
источник
2
Вы смотрели reifyInstances?
Kwarrtz
2
@Kwarrtz: я только что попробовал это сейчас. Это не работает, хотя; это просто приводит к тому же InstanceDs, что я видел с reify: putStrLn $(stringE . show =<< reifyInstances ''C' =<< sequence [[t|[Int]|]])оценивает [InstanceD [] (AppT (ConT Ghci1.C') (AppT ListT (VarT a_1627405978))) []], которому не хватает экземпляров семейства типов.
Антал Спектор-Забуский
1
Я нахожу странным, что reifyне возвращает необходимую информацию. Возможно show, скрывает часть информации? Вы пытались исследовать Infoобъект напрямую?
Kwarrtz
@Kwarrtz: боюсь Info, Showэкземпляр только производный, и то же самое для Showэкземпляра для Dec. Тем не менее, я также могу проверить напрямую, как вы просили, и нет: putStrLn $(reify ''C' >>= \i -> case i of ClassI (ClassD _ _ _ _ [SigD _ _]) _ -> stringE "just a SigD" ; _ -> stringE "something else")производит just a SigD- это действительно единственная вещь [Dec]в ClassD! (требуется LambdaCase). Я согласен, это странно; вот почему я задал этот вопрос :-)
Antal Spector-Zabusky
1
@Abel: Я думаю, что мы находимся в насильственном соглашении - ваш оригинальный комментарий сказал, что этого недостаточно, чтобы привлечь блестящую идею, но это действительно привлекло ответ Юраса! Я абсолютно согласен с тем, что хороший ответ :-)
Антал Спектор-Забуский

Ответы:

15

Это не реализовано, потому что никто не просил это.

Странно то, что TH использует свой собственный AST, который не следует AST внутреннего компилятора. В результате любая новая функция (например, связанные семейства типов) не будет автоматически доступна через TH. Кто-то должен открыть билет и реализовать его.

Для справки: внутренняя reifyClassфункция игнорирует связанные семейства типов (это 5-й элемент кортежа, возвращаемый функцией classExtraBigSig, см. Также определение ClassATItem.)

Технически это должно быть легко реализовать поддержку связанного семейства типов reify, но, скорее всего, это потребует обратной несовместимости изменений в TH API, например, потому что его AST, похоже, не поддерживает значения по умолчанию для связанного типа.

Добавлено: теперь оно реализовано (без изменения API) и, вероятно, будет доступно в следующем ghcвыпуске.

Юрась
источник
1
@ AntalS-Z Я имею в виду, что по умолчаниюFamilyD не поддерживается ассоциированный синоним типа . Возможно, вы их не используете, но для полного решения может потребоваться изменение API.
Юрас
5
@Abel, оставляя награду открытой до конца, также помогает хорошим ответам привлекать голоса, так что это более эффективный способ вознаграждения за хороший ответ, чем быстрое.
15:45
1
Период щедрости истек. Это лучший (и единственный) ответ до или до тех пор, пока не будет решен отчет об ошибке # 10891 . Возможно, хорошей идеей будет включить ссылку на отчет об ошибке в ваш ответ.
Авель
1
К вашему сведению, # 10891 исправлен и ожидает слияния.
Синан
1
@SwiftsNamesake AFAIK ghc devs хотят свободно менять внутренний AST, не нарушая TH API. Возможно, есть и другие причины.
Юрас