Obtenir des synonymes de types associés avec le modèle Haskell

257

Template Haskell peut-il connaître les noms et / ou les déclarations des synonymes de type associés déclarés dans une classe de type? Je m'attendais à reifyce que je fasse ce que je veux, mais cela ne semble pas fournir toutes les informations nécessaires. Cela fonctionne pour obtenir des signatures de type de fonction:

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

Cependant, l'ajout d'un synonyme de type associé à la classe n'entraîne aucun changement (jusqu'à renommer) dans la sortie:

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

Si je connais le nom de F, je peux rechercher des informations à ce sujet:

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

Mais je ne trouve pas le nom de Fen premier lieu. Même si j'ajoute une instance de la classe type, le InstanceDn'a aucune information sur la définition:

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

Si reifycela ne fonctionne pas, existe-t-il une solution de contournement, autre que la liste manuelle des synonymes de type associé?

Ce problème est présent dans GHC 7.8.3 avec la version 2.9.0.0 du package template-haskell; il était également présent dans GHC 7.4.2 avec la version 2.7.0.0 du package template-haskell. (Je n'ai pas vérifié GHC 7.6. *, Mais j'imagine qu'il y était aussi.) Je suis intéressé par des solutions pour n'importe quelle version de GHC (y compris "cela n'a été corrigé que dans GHC version V ").

Antal Spector-Zabusky
la source
2
Avez-vous regardé reifyInstances?
Kwarrtz
2
@Kwarrtz: Je viens de l'essayer maintenant. Cela ne fonctionne pas, cependant; il donne juste lieu aux mêmes InstanceDs que j'ai vu avec reify: putStrLn $(stringE . show =<< reifyInstances ''C' =<< sequence [[t|[Int]|]])évalue à [InstanceD [] (AppT (ConT Ghci1.C') (AppT ListT (VarT a_1627405978))) []], auquel il manque les instances de famille de types.
Antal Spector-Zabusky
1
Je trouve étrange que reifycela ne renvoie pas les informations nécessaires. Peut show- être cache-t-il certaines informations? Avez-vous essayé d'examiner Infodirectement l' objet?
Kwarrtz
@Kwarrtz: J'ai bien peur que Infol' Showinstance ne soit que dérivée, et même pour l' Showinstance de Dec. Cependant, je peux aussi vérifier directement, comme vous l'avez demandé, et non: putStrLn $(reify ''C' >>= \i -> case i of ClassI (ClassD _ _ _ _ [SigD _ _]) _ -> stringE "just a SigD" ; _ -> stringE "something else")produit just a SigD- c'est vraiment la seule chose [Dec]dans le ClassD! (nécessite LambdaCase). Je suis d'accord, c'est bizarre; c'est pourquoi j'ai posé cette question :-)
Antal Spector-Zabusky
1
@Abel: Je pense que nous sommes en accord violent - votre commentaire original disait que ce n'était pas suffisant pour attirer une idée brillante, mais cela a attiré la réponse de Yuras! Je suis absolument d'accord sur ce qu'est une bonne réponse :-)
Antal Spector-Zabusky

Réponses:

15

Il n'est pas implémenté car personne ne l'a demandé.

La chose étrange est que TH utilise son propre AST, qui ne suit pas l'AST du compilateur interne. Par conséquent, toute nouvelle fonctionnalité (par exemple, les familles de types associées) n'est pas automatiquement disponible via TH. Quelqu'un doit ouvrir un ticket et l'implémenter.

Pour la référence: la reifyClassfonction interne ignore les familles de types associées (c'est le 5ème élément du tuple retourné par classExtraBigSig, voir aussi la définition de ClassATItem.)

Techniquement, il devrait être facile d'implémenter la prise en charge de la famille de types associée reify, mais cela nécessitera très probablement des modifications incompatibles en amont dans l'API TH, par exemple parce que son AST ne semble pas prendre en charge les valeurs par défaut des types associés.

Ajouté: Il est maintenant implémenté (sans changement d'API btw) et sera probablement disponible dans la prochaine ghcversion.

Yuras
la source
1
@ AntalS-Z Je veux dire que FamilyDcela ne prend pas en charge les valeurs par défaut de synonyme de type associé . Vous ne les utilisez probablement pas, mais la solution complète peut nécessiter un changement d'API.
Yuras
5
@Abel, laisser la prime ouverte jusqu'à la fin a également tendance à aider les bonnes réponses à attirer des votes, c'est donc un moyen plus efficace de récompenser une bonne réponse que de l'attribuer rapidement.
dfeuer
1
La période de prime a expiré. C'est la meilleure (et la seule) réponse, jusqu'à ce que le rapport de bogue # 10891 soit résolu ou à moins que cela ne soit résolu . Peut-être une bonne idée d'inclure un lien vers le rapport de bogue dans votre réponse.
Abel
1
Pour info, # 10891 est corrigé et attend d'être fusionné.
sinan
1
Les développeurs de @SwiftsNamesake AFAIK ghc veulent changer l'AST interne librement sans casser l'API TH. Il y a probablement aussi d'autres raisons.
Yuras