查看 Template Haskell 生成的代码的首选方法

发布于 2024-12-21 20:26:21 字数 366 浏览 1 评论 0原文

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

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

将 TH 生成的 AST 转换为类似于普通 Haskell 代码的首选方法是什么,以便代码可以轻松阅读和理解?可以根据给定的 Dec 值重建源代码吗?是否必须阅读 GHC 核心代码?有没有一种方法至少可以构建 AST,使其变得更具可读性(超出 pretty-show 包的作用)?

As you know, Template Haskell is used to generate various kinds of AST splices programmatically at compile-time.

However, a splice can often be very opaque, and it is often difficult to discern what a splice actually generates. If you run the Q monad for a splice, and the splice is well-typed, you get a showable representation of the generated piece of AST, but this representation can be very difficult to understand, because of its unstructured layout.

What is the preferred method for converting a piece of TH-generated AST into something akin to normal Haskell code, so that the code can be easily read and understood? Can one reconstruct source code from e.g. a given Dec value? Does one have to read the GHC Core code? Is there a way to at least structure the AST so that it becomes more readable (Beyond what e.g. the pretty-show package does)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

一抹微笑 2024-12-28 20:26:22

您是否正在寻找编译器的 -ddump-splices 标志?

Are you looking for the -ddump-splices flag to the compiler?

只是一片海 2024-12-28 20:26:22

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

You may be able to use pprint or ppr from Language.Haskell.TH.Ppr (imported automatically with 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

It's not pretty, but it is valid Haskell. You should be able to make the output nicer by stripping off module prefixes from Prelude names (although you might need to be careful to only strip the expected prefix; Foo.* is a perfectly valid infix operator, after all).

神仙妹妹 2024-12-28 20:26:22

作为对第三个答案的补充:

请注意,直接从 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

As a complement to ehird answer:

Note that using runQ directly from GHCi
in general might not work
(e.g.: TH generators that use reify operations,
cf. comments above the runQ declaration).

When that fails, you can pprint (or show), transform intro a string expression stringE then splice as an argument to 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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文