假设我有fn begin
:(begin "hello")
。 `(begin "hello")
的结果为(my-ns/begin "hello")
。这很好。但现在我这样做:(def x '(begin "hello"))
。如何使用反引号扩展x
以获取(my-ns/begin "hello")
,而不只是(begin "hello")
?
答案 0 :(得分:3)
在第一个示例中,您使用了`
,这是一个名为" read-quote"的读者宏,在第二个示例中,您使用了'
这是一个名为&#的读者宏34;报价&#34 ;. Syntax-quote提供了quote
提供的一些功能:
~
,~@
等普通老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会一直使用你的代码