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, InstanceD
nie 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 reify
nie 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 ”).
źródło
reifyInstances
?InstanceD
jak widziałem zreify
: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.reify
nie zwraca niezbędnych informacji. Być możeshow
ukrywasz niektóre informacje? Czy próbowałeśInfo
bezpośrednio zbadać obiekt?Info
jestShow
wystąpienie jest tylko pochodzi jeden i ten sam dlaShow
przykładu doDec
. 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")
produkujejust a SigD
- to naprawdę jedyna rzecz na[Dec]
wClassD
! (wymagaLambdaCase
). Zgadzam się, że to dziwne; dlatego zadałem to pytanie :-)Odpowiedzi:
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:
reifyClass
funkcja wewnętrzna ignoruje skojarzone rodziny typów (jest to piąty element zwracanej przez krotkęclassExtraBigSig
, patrz także definicjaClassATItem
.)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
ghc
wersji.źródło
FamilyD
nie 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.