Zugehörige Typensynonyme mit Vorlage Haskell abrufen

257

Kann Template Haskell die Namen und / oder Deklarationen der zugehörigen Typensynonyme herausfinden, die in einer Typklasse deklariert sind? Ich hatte erwartet, reifydass ich tun würde, was ich will, aber es scheint nicht alle notwendigen Informationen zu liefern. Es funktioniert zum Abrufen von Funktionstypsignaturen:

% 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)))])
       []

Das Hinzufügen eines zugeordneten Typensynonyms zur Klasse bewirkt jedoch keine Änderung (bis zum Umbenennen) der Ausgabe:

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)))])
       []

Wenn ich den Namen von kenne F, kann ich Informationen darüber nachschlagen:

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

Aber ich kann den Namen überhaupt nicht finden F. Selbst wenn ich eine Instanz der Typklasse hinzufüge, enthält die InstanceDkeine Informationen zur Definition:

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)))
                  []]

Wenn dies reifynicht funktioniert, gibt es eine andere Problemumgehung als die manuelle Auflistung der Synonyme für den assoziierten Typ?

Dieses Problem tritt in GHC 7.8.3 mit Version 2.9.0.0 des Template-Haskell-Pakets auf. Es war auch in GHC 7.4.2 mit Version 2.7.0.0 des Template-Haskell-Pakets vorhanden. (Ich habe GHC 7.6 nicht überprüft. *, Aber ich kann mir vorstellen, dass es auch dort vorhanden war.) Ich bin an Lösungen für jede Version von GHC interessiert (einschließlich "Dies wurde nur in GHC Version V behoben ").

Antal Spector-Zabusky
quelle
2
Hast du angeschaut reifyInstances?
Kwarrtz
2
@ Kwarrtz: Ich habe es gerade versucht. Es funktioniert jedoch nicht; es entstehen nur die gleichen InstanceDs, wie ich sie gesehen habe reify: putStrLn $(stringE . show =<< reifyInstances ''C' =<< sequence [[t|[Int]|]])evaluiert zu [InstanceD [] (AppT (ConT Ghci1.C') (AppT ListT (VarT a_1627405978))) []], was den Instanzen der Typfamilie fehlt.
Antal Spector-Zabusky
1
Ich finde es seltsam, dass reifynicht die notwendigen Informationen zurückgegeben werden. Vielleicht showversteckt sich ein Teil der Informationen? Haben Sie versucht, das InfoObjekt direkt zu untersuchen?
Kwarrtz
@ Kwarrtz: Ich fürchte Info, die ShowInstanz ist nur die abgeleitete und die gleiche für die ShowInstanz für Dec. Ich kann aber auch direkt nachsehen, wie Sie gefragt haben, und nein: putStrLn $(reify ''C' >>= \i -> case i of ClassI (ClassD _ _ _ _ [SigD _ _]) _ -> stringE "just a SigD" ; _ -> stringE "something else")produziert just a SigD- das ist wirklich das einzige, was [Dec]in der ClassD! (erfordert LambdaCase). Ich bin damit einverstanden, dass es seltsam ist; Deshalb habe ich diese Frage gestellt :-)
Antal Spector-Zabusky
1
@Abel: Ich denke, wir sind uns einig - Ihr ursprünglicher Kommentar sagte, es sei nicht genug, um eine brillante Idee zu gewinnen, aber es hat Yuras 'Antwort angezogen! Ich stimme absolut zu, was eine gute Antwort ist :-)
Antal Spector-Zabusky

Antworten:

15

Es ist nicht implementiert, weil niemand es angefordert hat.

Das Seltsame ist, dass TH einen eigenen AST verwendet, der nicht dem AST des internen Compilers folgt. Infolgedessen ist eine neue Funktion (z. B. zugehörige Typenfamilien) nicht automatisch über TH verfügbar. Jemand muss ein Ticket öffnen und implementieren.

Als Referenz: Die interne reifyClassFunktion ignoriert zugehörige Typfamilien (dies ist das 5. Element des von zurückgegebenen Tupels classExtraBigSig, siehe auch Definition von ClassATItem.)

Technisch sollte es einfach sein, die Unterstützung für zugeordnete Typfamilien in zu implementieren reify, aber höchstwahrscheinlich sind abwärtsinkompatible Änderungen in der TH-API erforderlich, z. B. weil der AST die zugehörigen Typstandards nicht zu unterstützen scheint.

Hinzugefügt: Es ist jetzt implementiert (übrigens ohne API-Änderung) und wird wahrscheinlich in der nächsten ghcVersion verfügbar sein .

Yuras
quelle
1
@ AntalS-Z Ich meine, dass FamilyDdie zugehörigen Standardeinstellungen für Typensynonyme nicht unterstützt werden . Sie verwenden sie wahrscheinlich nicht, aber für die vollständige Lösung ist möglicherweise eine API-Änderung erforderlich.
Yuras
5
@Abel: Wenn Sie das Kopfgeld bis zum Ende offen lassen, können gute Antworten auch dazu beitragen, Stimmen zu gewinnen. Daher ist es eine effektivere Möglichkeit, eine gute Antwort zu belohnen, als sie schnell zu vergeben.
dfeuer
1
Kopfgeldzeitraum abgelaufen. Dies ist die beste (und einzige) Antwort, bis oder bis der Fehlerbericht # 10891 behoben ist . Vielleicht ist es eine gute Idee, einen Link zum Fehlerbericht in Ihre Antwort aufzunehmen.
Abel
1
Zu Ihrer Information, # 10891 ist behoben und wartet darauf, zusammengeführt zu werden.
Sinan
1
@SwiftsNamesake AFAIK ghc-Entwickler möchten den internen AST frei ändern, ohne die TH-API zu beschädigen. Wahrscheinlich gibt es auch andere Gründe.
Yuras