首选查看Template Haskell生成的代码的方法是什么?

45

如您所知,模板 Haskell 用于在编译时以编程方式生成各种AST Splices。

然而,Splice 经常是非常不透明的,往往很难辨别 Splice 实际生成了什么。如果您对 Splice 运行 Q Monad,并且 Splice 是良好类型化的,那么您会得到一个可显示的 AST 生成片段的表示,但由于其无结构布局,此表示可能非常难以理解。

将一段 TH 生成的 AST 转换为类似普通 Haskell 代码的首选方法是什么,以便可以轻松阅读和理解代码?可以从给定的 Dec 值重建源代码吗?必须阅读 GHC Core 代码吗?是否有一种方法可以使用结构来使 AST 变得更具可读性(超出 pretty-show 等工具的范围)?

3个回答

58

你是否在寻找向编译器传递 -ddump-splices 标志的方法?


2
是的,这种输出正是我要找的!但是如果只有语法树,是否可以在程序中完成,还是需要调用编译器? - dflemstr
2
请注意:在运行此程序之前,请确保删除.hi和.o文件以获得干净的构建,否则您将无法获得任何stderr输出。 - RussellStewart

25

您可以尝试使用Language.Haskell.TH.Ppr中的pprintppr(自动导入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.* 是一个完全有效的中缀运算符)。


这解决了@augustss没有回答的问题的一部分。 - dflemstr

1
作为ehird answer的补充:
请注意,通常直接从GHCi中使用runQ可能不起作用(例如:使用reify操作的TH生成器,参见在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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接