4

考虑这段代码:

魔术 :: String -> Q Exp
魔法 s = [e| putStrLn s |]

现在,据我所知,这实际上是行不通的。在牛津括号内,s不在范围内。然而,上述显然是完美的。

如果我们稍微改变一下这个例子,它现在会很糟糕:

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

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

有谁知道这到底是怎么回事?

4

2 回答 2

12

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

例如,s的Lift实例Integer简单地构造相应的整数文字,而实例 forMaybe简单地构造适当的构造函数应用程序。您甚至可以定义自己的Lift.

您收到“无实例”错误,因为nis a Name,它不能Lift

于 2012-03-06T17:19:15.197 回答
2

我认为简短的回答是,魔术函数预计会起作用,因为引号确实捕获了它们的局部变量(以某种方式)。本质上,引号中的编译时局部变量被它们的文字值替换并成为运行时常量。这是通过隐式调用 lift 函数来实现的,因此 [| .. var .. |] 变成 [| $(电梯变量)|]。

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

如果它有帮助,我个人认为引号是“拼接生成器”——Haskell 代码的小片段,它们将在编译时转换为 AST,因此将成为可以插入任何地方的拼接。正如 Bulat 的教程(来自 的链接)所指出的,它们的作用类似于宏预处理器的一种形式,因为它们是 Haskell 函数生成代码和将 Haskell 代码简单地自动转换为 TH AST 的混合体。

编辑:似乎 ehird 击败了我 - 我留下我的答案,以防它提供一些额外的价值。

于 2012-03-06T17:22:14.450 回答