为什么这个模板Haskell工作?

考虑这个代码:

magic :: String -> Q Exp
magic s = [e| putStrLn s |]

现在,尽我所知,这实际上并不适用。 在牛津括号内, s不在范围内。 然而,上述显然完美的作品。

如果我们稍微改变这个例子,它现在会破坏得很厉害:

magic :: Exp -> Q Exp
magic (VarE n) = [e| putStrLn (nameBase n) |]

就像以前一样,我们有一个不在范围内的变量。 这一次,它打破了。 但它并不抱怨一个不在范围内的变量; 相反,它会抱怨一些缺乏实例的无证班级。

任何人都知道这是怎么回事?


s范围在牛津括号内。 基本上,您可以在引用的表达式中使用多种类型的值(包含Lift实例的值),并且它们会自动转换为适当的代码以在另一端重新创建相应的值。

例如, IntegerLift实例只是构造相应的整型文本,而Maybe的实例只是构造适当的构造函数应用程序。 你甚至可以定义你自己的Lift实例。

你得到一个“没有实例”的错误,因为n是一个Name ,这不是Lift能够。


我认为最简单的答案是魔术功能预计会发挥作用,因为引号括起来会捕获它们的局部变量(以某种方式)。 本质上,引号括起来的编译时局部变量被它们的字面值取代并成为运行时常量。 这是通过隐式调用lift函数来实现的,所以[| .. var .. |]变成[| $(lift var)|]。

也许你会将这种行为与它们唯一捕获局部变量的事实相混淆,这样重复调用相同的引用就不会干扰彼此的变量名称。 这是通过在幕后调用newName来实现的,这确保了唯一的变量名称。

如果有帮助,我个人认为引号是“拼接生成器” - 在编译时将会被转换为AST的一小段Haskell代码,因此将成为拼接准备插入任何地方。 正如Bulat的教程(来自链接)指出的那样,它们就像一种宏观预处理器,因为它们是Haskell函数生成代码的混合体,以及将Haskell代码简单自动转换为TH AST的混合体。

编辑:似乎ehird打我的答案 - 我离开我的答案,以防万一它提供了一些额外的价值。

链接地址: http://www.djcxy.com/p/5673.html

上一篇: Why does this Template Haskell work?

下一篇: Orphaned instances in Haskell