253

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

% 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: Я просто попробовал это сейчас. Однако это не работает; это просто приводит к тому же 'InstanceD', как я видел с 'reify':' putStrLn $ (stringE. show = << reifyInstances '' C '= << sequence [[t | [Int] |]]) ' оценивает '[InstanceD [] (AppT (ConT Ghci1.C ') (AppT ListT (VarT a_1627405978))) []]', в котором отсутствуют экземпляры семейства типов. –

+1

Мне кажется странным, что 'reify' не возвращает необходимую информацию. Возможно, 'show' скрывает часть информации? Вы пытались напрямую изучить объект «Info»? – Kwarrtz

ответ

13

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

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

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

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

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

+0

Спасибо, Юрас! Я также зарегистрировал [сообщение об ошибке # 10891] (https://ghc.haskell.org/trac/ghc/ticket/10891) об этом. Обратите внимание, что я не думаю, что это несовместимо с обратной связью (но не цитируйте меня на этом): 'reify' возвращает' ClassI', содержащий ['ClassD'] (http://hackage.haskell.org/package/ template-haskell-2.10.0.0/docs/Language-Haskell-TH-Syntax.html # v: ClassD), который содержит '[Dec]', и я ожидал, что один из этих 'Dec' будет ['FamilyD '] (http://hackage.haskell.org/package/template-haskell-2.10.0.0/docs/Language-Haskell-TH-Syntax.html#v:FamilyD), который уже существует. –

+0

Только то, что мне нужно. Но я оставлю щедрость открытой [до льготного периода] (http://blog.stackoverflow.com/2011/09/bounty-reasons-and-post-notices/), чтобы позволить другим комментировать и/или доказывать вы ошибаетесь;) – Abel

+1

@ AntalS-Z Я имею в виду, что 'FamilyD' не поддерживает [связанные синтаксические значения по умолчанию] (https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/type-families .html # ассоциативный Децл-DEFS). Вероятно, вы их не используете, но для полного решения может потребоваться изменение API. – Yuras