Obteniendo sinónimos de tipos asociados con la plantilla Haskell

257

¿Puede Template Haskell descubrir los nombres y / o las declaraciones de los sinónimos de tipo asociados declarados en una clase de tipo? Esperaba reifyhacer lo que quisiera, pero no parece proporcionar toda la información necesaria. Funciona para obtener firmas de tipo de función:

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

Sin embargo, agregar un sinónimo de tipo asociado a la clase no causa ningún cambio (hasta el cambio de nombre) en la salida:

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 sé el nombre de F, puedo buscar información al respecto:

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

Pero no puedo encontrar el nombre de Fen primer lugar. Incluso si agrego una instancia de la clase de tipo, InstanceDno tiene ninguna información sobre la definición:

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 reifyno funciona, ¿hay alguna solución alternativa, aparte de enumerar los sinónimos de tipo asociado manualmente?

Este problema está presente en GHC 7.8.3 con la versión 2.9.0.0 del paquete template-haskell; también estuvo presente en GHC 7.4.2 con la versión 2.7.0.0 del paquete template-haskell. (No verifiqué en GHC 7.6. *, Pero imagino que también estuvo presente allí.) Estoy interesado en soluciones para cualquier versión de GHC (incluyendo "esto solo se solucionó en la versión V de GHC ").

Antal Spector-Zabusky
fuente
2
¿Has mirado reifyInstances?
Kwarrtz
2
@Kwarrtz: Acabo de probarlo ahora. Sin embargo, no funciona; solo da lugar a los mismos InstanceDs que vi con reify: putStrLn $(stringE . show =<< reifyInstances ''C' =<< sequence [[t|[Int]|]])evalúa a [InstanceD [] (AppT (ConT Ghci1.C') (AppT ListT (VarT a_1627405978))) []], que carece de las instancias de tipo de familia.
Antal Spector-Zabusky
1
Me resulta extraño que reifyno devuelva la información necesaria. ¿Quizás showestá ocultando parte de la información? ¿Has intentado examinar el Infoobjeto directamente?
Kwarrtz
@Kwarrtz: Me temo que Infola Showinstancia es solo la derivada, e igual para la Showinstancia de Dec. Sin embargo, también puedo verificar directamente, como usted pidió, y no: putStrLn $(reify ''C' >>= \i -> case i of ClassI (ClassD _ _ _ _ [SigD _ _]) _ -> stringE "just a SigD" ; _ -> stringE "something else")produce just a SigD- ¡eso es realmente lo único [Dec]en el ClassD! (requiere LambdaCase) Estoy de acuerdo en que es extraño; por eso hice esta pregunta :-)
Antal Spector-Zabusky
1
@Abel: Creo que estamos de acuerdo violenta - su comentario original, dijo que no era suficiente para atraer una idea brillante, pero lo hizo atraer la respuesta de Yuras! Estoy totalmente de acuerdo con lo que es una buena respuesta :-)
Antal Spector-Zabusky

Respuestas:

15

No se implementa porque nadie lo solicitó.

Lo extraño es que TH usa su propio AST, que no sigue el AST del compilador interno. Como resultado, cualquier característica nueva (por ejemplo, familias de tipos asociadas) no está disponible automáticamente a través de TH. Alguien tiene que abrir un ticket e implementarlo.

Para la referencia: la reifyClassfunción interna ignora las familias de tipos asociadas (es el quinto elemento de la tupla devuelto por classExtraBigSig, vea también la definición de ClassATItem).

Técnicamente, debería ser fácil implementar el soporte de familias de tipos asociados reify, pero lo más probable es que requiera cambios incompatibles con versiones anteriores en TH API, por ejemplo, porque su AST no parece admitir los valores predeterminados de tipos asociados.

Agregado: ahora está implementado (sin cambio de API por cierto) y probablemente estará disponible en la próxima ghcversión.

Yuras
fuente
1
@ AntalS-Z Quiero decir que FamilyDno admite valores predeterminados de sinónimos asociados . Probablemente no los esté utilizando, pero la solución completa puede requerir un cambio de API.
Yuras
55
@Abel, dejar la recompensa abierta hasta el final también tiende a ayudar a que las buenas respuestas atraigan votos, por lo que es una forma más efectiva de recompensar una buena respuesta que otorgarla rápidamente.
dfeuer
1
El período de recompensa expiró. Esta es la mejor (y única) respuesta, hasta que el informe de error # 10891 se resuelva o no . Quizás sea una buena idea incluir un enlace al informe de error en su respuesta.
Abel
1
FYI, # 10891 está arreglado y está esperando ser fusionado.
sinan
1
Los desarrolladores de @SwiftsNamesake AFAIK ghc quieren cambiar libremente el AST interno sin romper la API de TH. Probablemente hay otras razones también.
Yuras