Obtendo sinônimos de tipo associado ao modelo Haskell

257

O Template Haskell pode descobrir os nomes e / ou as declarações dos sinônimos de tipo associados declarados em uma classe de tipo? Eu esperava reifyque fizesse o que eu quero, mas parece não fornecer todas as informações necessárias. Ele funciona para obter assinaturas de tipo de função:

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

No entanto, adicionar um sinônimo de tipo associado à classe não causa alterações (até renomear) na saída:

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

Se eu souber o nome F, posso procurar informações sobre ele:

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

Mas não consigo encontrar o nome de Fem primeiro lugar. Mesmo se eu adicionar uma instância da classe type, InstanceDela não possui nenhuma informação sobre a definição:

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

Se reifynão funcionar, existe uma solução alternativa, além de listar os sinônimos do tipo de associado manualmente?

Esse problema está presente no GHC 7.8.3 com a versão 2.9.0.0 do pacote template-haskell; também estava presente no GHC 7.4.2 com a versão 2.7.0.0 do pacote template-haskell. (Eu não verifiquei o GHC 7.6. *, Mas imagino que ele estivesse presente também.) Estou interessado em soluções para qualquer versão do GHC (incluindo "isso foi corrigido apenas na versão V do GHC ").

Antal Spector-Zabusky
fonte
2
Você já olhou reifyInstances?
Kwarrtz
2
@Kwarrtz: Eu apenas tentei agora. Mas não funciona; apenas dá origem aos mesmos InstanceDs que vi com reify: putStrLn $(stringE . show =<< reifyInstances ''C' =<< sequence [[t|[Int]|]])avalia para [InstanceD [] (AppT (ConT Ghci1.C') (AppT ListT (VarT a_1627405978))) []], o que não possui as instâncias de família de tipo.
Antal Spector-Zabusky
1
Acho estranho que reifynão retorne as informações necessárias. Talvez showesteja escondendo algumas informações? Você já tentou examinar o Infoobjeto diretamente?
Kwarrtz
@ Kwarrtz: Receio que Infoa Showinstância seja apenas a derivada e a mesma para a Showinstância Dec. No entanto, também posso verificar diretamente, como você pediu, e não: putStrLn $(reify ''C' >>= \i -> case i of ClassI (ClassD _ _ _ _ [SigD _ _]) _ -> stringE "just a SigD" ; _ -> stringE "something else")produz just a SigD- essa é realmente a única coisa no [Dec]in ClassD! (requer LambdaCase). Eu concordo que é estranho; é por isso que eu fiz esta pergunta :-)
Antal Spector-Zabusky
1
@Abel: Eu acho que estamos de acordo violenta - o seu comentário original disse que não era o suficiente para atrair uma idéia brilhante, mas fez atrair a resposta de Yuras! Estou absolutamente de acordo sobre o que uma boa resposta é :-)
Antal Spector-Zabusky

Respostas:

15

Não foi implementado porque ninguém solicitou.

O curioso é que o TH usa seu próprio AST, que não segue o AST do compilador interno. Como resultado, qualquer novo recurso (por exemplo, famílias de tipos associados) não está disponível automaticamente via TH. Alguém tem que abrir um ticket e implementá-lo.

Para a referência: a reifyClassfunção interna ignora famílias de tipos associadas (é o quinto elemento da tupla retornado por classExtraBigSig, consulte também a definição de ClassATItem.)

Tecnicamente, deve ser fácil implementar o suporte à família de tipos associados reify, mas é mais provável que exija mudanças incompatíveis com a API TH, por exemplo, porque seu AST não parece suportar os padrões de tipos associados.

Adicionado: agora está implementado (sem alteração da API btw) e provavelmente estará disponível na próxima ghcversão.

Yuras
fonte
1
@ AntalS-Z Quero dizer que FamilyDnão suporta padrões associados de sinônimos de tipo . Você provavelmente não os está usando, mas a solução completa pode exigir alterações na API.
Yuras 17/09/2015
5
@Abel, deixar a recompensa em aberto até o final também tende a ajudar boas respostas a atrair votos, por isso é uma maneira mais eficaz de recompensar uma boa resposta do que concedê-la rapidamente.
Dfeuer
1
O período de recompensa expirou. Esta é a melhor (e única) resposta, até ou a menos que o relatório de bug # 10891 seja resolvido . Talvez seja uma boa ideia incluir um link para o relatório de erros em sua resposta.
Abel
1
Para sua informação, o número 10891 foi corrigido e aguarda sua fusão.
sinan 22/09/2015
1
O @SwiftsNamesake AFAIK ghc devs deseja alterar livremente o AST interno sem interromper a API do TH. Provavelmente há outras razões também.
Yuras 31/08/17