嵌套的引用和扩展

时间:2014-12-08 06:05:38

标签: macros clojure

假设我有fn begin(begin "hello")`(begin "hello")的结果为(my-ns/begin "hello")。这很好。但现在我这样做:(def x '(begin "hello"))。如何使用反引号扩展x以获取(my-ns/begin "hello"),而不只是(begin "hello")

1 个答案:

答案 0 :(得分:3)

在第一个示例中,您使用了`,这是一个名为" read-quote"的读者宏,在第二个示例中,您使用了'这是一个名为&#的读者宏34;报价&#34 ;. Syntax-quote提供了quote提供的一些功能:

  • 取消引用~~@
  • 用于编写hygenic宏的符号的命名空间扩展。

普通老quote没有这些。因此,如果您想在两个示例中使用名称空间扩展,请在两个位置使用`。如果要在语法排序列表中获取非命名空间符号,可以同时使用它们`(println ~'symbol-name),它们将仅评估为(println symbol-name)。 (在这种情况下,需要在调用它的命名空间中定义符号名称(此过程称为"符号捕获"))。语法引用首先评估对引用的调用,然后依次计算符号。

如果您希望扩展由于某种原因已经存在的符号,或者您想要在几个不同的名称空间中展开它,那么您可以使用ns-resolve函数:

(ns-resolve *ns* 'begin)

因此,在您的示例中,您可以将其映射到列表上,以使用NS限定符号进行打印:

user> (map #(if (symbol? %) (ns-resolve *ns*  %) %) x)
(#'user/begin "hello")

虽然这不是正好所需的输出,因为它引用了该命名空间中的var而不是解析为此var的符号。这里的事情有点冒险,因为`是一个读者宏,我们无法在其他宏中构建对它的调用。例如,我认为没办法写:

(defmacro expand-x [thing] 
  `(syntax-quote-here ~thing)

因为据我所知,syntax-quote没有名字(因为它是一个读者宏)所以在上面的例子中没有什么可以用来代替语法 - 引用 - 这里。虽然从来没有害怕,但在eval语言中,没有什么是不可能的,事情就会变得任意丑陋:

user> (eval (read-string (str "`" x)))
(user/begin "hello")

PS:实际上并没有使用最后一个例子,或者gremlins会一直使用你的代码