Uzyskiwanie skojarzonych synonimów typów z szablonem Haskell

257

Czy szablon Haskell może znaleźć nazwy i / lub deklaracje powiązanych synonimów typów zadeklarowanych w klasie typu? Spodziewałem się, reifyże zrobię to, co chcę, ale wydaje się, że nie zawiera wszystkich niezbędnych informacji. Działa w celu uzyskania podpisów typów funkcji:

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

Jednak dodanie do klasy synonimu powiązanego nie powoduje żadnych zmian (aż do zmiany nazwy) w danych wyjściowych:

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

Jeśli znam nazwę F, mogę wyszukać informacje na jej temat:

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

Ale nie mogę znaleźć nazwy F. Nawet jeśli dodam instancję klasy typu, InstanceDnie zawiera ona żadnych informacji o definicji:

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

Jeśli reifynie zadziała, czy istnieje inne obejście niż ręczne wyświetlanie synonimów typu stowarzyszonego?

Ten problem występuje w GHC 7.8.3 w wersji 2.9.0.0 pakietu template-haskell; był także obecny w GHC 7.4.2 z wersją 2.7.0.0 pakietu szablon-haskell. (Nie sprawdziłem GHC 7.6. *, Ale wyobrażam sobie, że tam też był obecny.) Interesują mnie rozwiązania dla dowolnej wersji GHC (w tym „naprawiono to tylko w wersji V GHC ”).

Antal Spector-Zabusky
źródło
2
Czy spojrzał reifyInstances?
Kwarrtz
2
@Kwarrtz: Właśnie tego spróbowałem. Ale to nie działa; po prostu daje takie same wyniki, InstanceDjak widziałem z reify: putStrLn $(stringE . show =<< reifyInstances ''C' =<< sequence [[t|[Int]|]])ewaluuje do [InstanceD [] (AppT (ConT Ghci1.C') (AppT ListT (VarT a_1627405978))) []], w którym brakuje instancji rodziny typów.
Antal Spector-Zabusky
1
Uważam to za dziwne, że reifynie zwraca niezbędnych informacji. Być może showukrywasz niektóre informacje? Czy próbowałeś Infobezpośrednio zbadać obiekt?
Kwarrtz
@Kwarrtz: Obawiam się, że Infojest Showwystąpienie jest tylko pochodzi jeden i ten sam dla Showprzykładu do Dec. Jednakże, mogę też sprawdzić bezpośrednio, jak prosiłeś, a nie: putStrLn $(reify ''C' >>= \i -> case i of ClassI (ClassD _ _ _ _ [SigD _ _]) _ -> stringE "just a SigD" ; _ -> stringE "something else")produkuje just a SigD- to naprawdę jedyna rzecz na [Dec]w ClassD! (wymaga LambdaCase). Zgadzam się, że to dziwne; dlatego zadałem to pytanie :-)
Antal Spector-Zabusky
1
@Abel: Myślę, że jesteśmy w gwałtownej umowy - oryginalny komentarz powiedział, że to nie wystarczy, aby przyciągnąć genialny pomysł, ale nie przyciągają odpowiedź Juraś głównej! Absolutnie zgadzam się co do dobrej odpowiedzi :-)
Antal Spector-Zabusky

Odpowiedzi:

15

Nie jest zaimplementowany, ponieważ nikt o to nie prosił.

Dziwne jest to, że TH używa własnego AST, który nie jest zgodny z AST wewnętrznego kompilatora. W rezultacie żadna nowa funkcja (np. Powiązane rodziny typów) nie jest automatycznie dostępna za pośrednictwem TH. Ktoś musi otworzyć bilet i wdrożyć go.

Dla odniesienia: reifyClassfunkcja wewnętrzna ignoruje skojarzone rodziny typów (jest to piąty element zwracanej przez krotkę classExtraBigSig, patrz także definicja ClassATItem.)

Technicznie powinno być łatwo wdrożyć obsługę rodziny typów powiązanych reify, ale najprawdopodobniej będzie wymagało wstecznie niekompatybilnych zmian w TH API, np. Ponieważ jego AST nie wydaje się obsługiwać domyślnych typów skojarzonych.

Dodano: Jest teraz zaimplementowany (bez zmiany API btw) i prawdopodobnie będzie dostępny w następnej ghcwersji.

Yuras
źródło
1
@ AntalS-Z Mam na myśli, że FamilyDnie obsługuje domyślnych synonimów powiązanych typów . Prawdopodobnie ich nie używasz, ale pełne rozwiązanie może wymagać zmiany interfejsu API.
Yuras
5
@Abel, pozostawianie nagrody otwartej do końca również pomaga dobrym odpowiedziom w przyciąganiu głosów, więc jest to bardziej skuteczny sposób na nagrodzenie dobrej odpowiedzi niż szybkie jej przyznanie.
dfeuer
1
Upłynął okres nagród. To najlepsza (i jedyna) odpowiedź, dopóki raport o błędzie nr 10891 nie zostanie rozwiązany . Być może dobrym pomysłem jest umieszczenie w odpowiedzi linku do raportu o błędzie.
Abel
1
Do Twojej wiadomości # 10891 jest naprawiony i czeka na połączenie.
sinan
1
@SwiftsNamesake AFAIK deweloperzy ghc chcą dowolnie zmieniać wewnętrzną AST bez łamania TH API. Prawdopodobnie są też inne powody.
Yuras,