2011-12-15 15 views
36

Como ya sabe, la plantilla Haskell se utiliza para generar diversos tipos de empalmes AST programáticamente en tiempo de compilación.Método preferido para ver el código generado por la plantilla Haskell

Sin embargo, un empalme a menudo puede ser muy opaco, y a menudo es difícil discernir lo que realmente genera un empalme. Si ejecuta la mónada Q para un empalme, y el empalme está bien tipado, obtendrá una representación capaz show de la pieza generada de AST, pero esta representación puede ser muy difícil de entender, debido a su diseño no estructurado.

¿Cuál es el método preferido para convertir una pieza de AST generada por TH en algo similar al código Haskell normal, para que el código pueda leerse y entenderse fácilmente? ¿Se puede reconstruir el código fuente de, p. un valor dado Dec? ¿Hay que leer el código GHC Core? ¿Hay alguna forma de estructurar al menos el AST para que sea más legible (más allá de lo que, por ejemplo, el paquete pretty-show)?

Respuesta

22

Usted puede ser capaz de utilizar pprint o ppr de Language.Haskell.TH.Ppr (importado de forma automática con Language.Haskell.TH):

GHCi> expr <- runQ [| \f g x -> f (x*2 + 3) . g |] 
GHCi> putStrLn $ pprint expr 
\f_0 g_1 x_2 -> f_0 ((x_2 GHC.Num.* 2) GHC.Num.+ 3) GHC.Base.. g_1 

No es bonito, pero es Haskell válida. Debería poder hacer que la salida sea más agradable eliminando los prefijos de los módulos de los nombres de los Preludios (aunque es posible que tenga que tener cuidado de solo quitar el prefijo esperado; Foo.* es un operador infijo perfectamente válido, después de todo).

+0

Esto resuelve la parte de la pregunta que @augustss no respondió. – dflemstr

46

¿Está buscando la bandera -ddump-splices para el compilador?

+2

Sí, este tipo de salida es precisamente lo que estoy buscando ! Pero, ¿se puede hacer esto en un programa dado solo un árbol de sintaxis, o requiere la invocación del compilador? – dflemstr

+1

nota: asegúrese de eliminar archivos .hi y .o para obtener una compilación limpia antes de ejecutar esto, o no obtendrá ninguna salida de stderr. – RussellStewart

1

Como complemento a ehird answer:

Tenga en cuenta que el uso de runQ directamente de GHCi en general podría no funcionar (por ejemplo los generadores TH .: reify que utilizan operaciones, cf. comments above the runQ declaration).

Cuando eso falla, puede pprint (o show), transformar introducción de una expresión de cadena stringE luego empalmar como argumento para putStrLn:

> putStrLn $(stringE . pprint =<< [| \f g x -> f (x*2 + 3) . g |]) 
\f_0 g_1 x_2 -> f_0 ((x_2 GHC.Num.* 2) GHC.Num.+ 3) GHC.Base.. g_1 
Cuestiones relacionadas