2011-12-15 2 views
36

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

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

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

ответ

22

Вы можете быть в состоянии использовать 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.* - совершенно корректный оператор инфикса).

+0

Это решает вопрос, который @augustss не ответил. – dflemstr

46

Вы ищете флаг -ddump-splices?

+2

Да, этот вид продукции является именно то, что я ищу ! Но может ли это быть сделано в программе, которая также дает только синтаксическое дерево или требует вызова компилятора? – dflemstr

+1

note: убедитесь, что вы удаляете файлы .hi и .o, чтобы получить чистую сборку, прежде чем запускать ее, или вы не получите никакого выхода stderr. – RussellStewart

1

В качестве дополнения к ehird answer:

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

Когда это не удается, вы можете pprint (или show), преобразование введения строкового выражения 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 
Смежные вопросы