45

如您所知,Template Haskell 用于在编译时以编程方式生成各种 AST 拼接。

但是,接头通常非常不透明,并且通常很难辨别接头实际生成的内容。如果您Q为拼接运行 monad,并且拼接是正确类型的,您将获得show生成的 AST 片段的有效表示,但由于其非结构化布局,这种表示可能很难理解。

将一段 TH 生成的 AST 转换为类似于普通 Haskell 代码的东西的首选方法是什么,以便代码易于阅读和理解?可以从例如给定Dec值重构源代码吗?是否必须阅读 GHC 核心代码?有没有办法至少构建 AST 以使其更具可读性(超出例如pretty-show包的功能)?

4

3 回答 3

56

你在寻找-ddump-splices编译器的标志吗?

于 2011-12-15T14:11:05.267 回答
25

您可以使用pprintpprLanguage.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.*毕竟是一个完全有效的中缀运算符)。

于 2011-12-15T14:44:26.637 回答
1

作为对ehird 答案的补充:

请注意,runQ通常直接从 GHCi 使用可能不起作用(例如:使用reify操作的 TH 生成器,参见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
于 2015-12-14T22:01:50.400 回答