Предпочтительный метод просмотра кода, сгенерированного Template Haskell

Как вы знаете, Template Haskell используется для программной генерации различных видов сплайсов AST во время компиляции.

Однако сращивание часто может быть очень непрозрачным, и часто бывает трудно различить, что на самом деле генерируется сплайсингом. Если вы запускаете монаду Q для соединения, и соединение хорошо типизировано, вы получаете showable представление сгенерированного фрагмента AST, но это представление может быть очень трудным для понимания из-за его неструктурированного макета.

Каков предпочтительный метод преобразования фрагмента AST, сгенерированного TH, во что-то похожее на обычный код Haskell, чтобы код можно было легко читать и понимать? Можно ли восстановить исходный код, например, из заданное значение Dec? Нужно ли читать код GHC Core? Есть ли способ хотя бы структурировать AST, чтобы он стал более читабельным (помимо того, что, например, делает пакет pretty-show)?


person dflemstr    schedule 15.12.2011    source источник


Ответы (3)


Вы можете использовать pprint или ppr из Language.Haskell.TH.Ppr (автоматически импортируется вместе с 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

Это не красиво, но это действительно Haskell. Вы должны иметь возможность сделать вывод более приятным, удалив префиксы модулей из имен Prelude (хотя вам, возможно, придется быть осторожным, удаляя только ожидаемый префикс; в конце концов, Foo.* — вполне допустимый инфиксный оператор).

person ehird    schedule 15.12.2011
comment
Это решает часть вопроса, на который @augustss не ответил. - person dflemstr; 15.12.2011

Вы ищете флаг -ddump-splices для компилятора?

person augustss    schedule 15.12.2011
comment
Да, такой выход - это именно то, что я ищу! Но можно ли это сделать и в программе, имеющей только синтаксическое дерево, или для этого требуется вызов компилятора? - person dflemstr; 15.12.2011
comment
примечание: убедитесь, что вы удалили файлы .hi и .o, чтобы получить чистую сборку, прежде чем запускать это, иначе вы не получите никакого вывода stderr. - person RussellStewart; 19.09.2014

В дополнение к третьему ответу:

Обратите внимание, что использование runQ непосредственно из GHCi в целом может не работать (например, генераторы TH, использующие операции reify, см. комментарии над объявлением runQ).

Если это не удается, вы можете pprint (или show) преобразовать intro в строковое выражение stringE, а затем вставить его в качестве аргумента в 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
person Rudy Matela    schedule 14.12.2015