Предпочтительный метод для просмотра кода, сгенерированного шаблоном Haskell - PullRequest
40 голосов
/ 15 декабря 2011

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

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

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

Ответы [ 3 ]

52 голосов
/ 15 декабря 2011

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

22 голосов
/ 15 декабря 2011

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

1 голос
/ 15 декабря 2015

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

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

Когда это не удается, вы можете 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
...