为什么Clojure在反引号内添加命名空间限定符?

9

我正在尝试以编程方式构建数据日志查询,但是始终遇到一个问题,我将通过以下示例函数说明:

(defn test-expr [attribute]
  `[?entity ~attribute ?value]])

当我运行(test-expr 3)时,我期望输出:
 [?entity 3 ?value]

但是实际上,我得到的是:
[mynamespace/?entity 3 mynamespace/?value]

显然这不是我想要的。有没有办法告诉Clojure“请只引用列表并扩展我告诉你的变量?”

1
至于原因,这是为了防止用户(咳咳你)意外地通过定义与您使用的名称相同的函数和/或变量来破坏您的宏。 - Cubic
@Cubic,同意。据我所知,这是Scheme卫生宏和Common Lisp普通宏系统之间某种妥协:宏定义看起来几乎与Common Lisp相同(这很好,因为我认为Scheme宏更难编写),但默认情况下存在一定程度的卫生性 - 符号不会被盲目捕获,而是加上命名空间前缀。当需要时,总是可以回退到纯替换(例如用于指示宏)。 - Vladimir Matveev
2个回答

12

有的。

(defn test-expr [attribute]
  `[~'?entity ~attribute ~'?value])

在这里,您首先取消引用语法引用,然后立即再次引用符号(~'结构)。结果是无命名空间的符号。

它等同于以下内容,说明它的工作原理:

(defn test-expr [attribute]
  `[~(quote ?entity) ~attribute ~(quote ?value)])

7
您要找的是Brandon Bloom的反引号库,https://github.com/brandonbloom/backtick。该库为您提供了一个名为“template”的命令,它的工作原理类似于反引号,但没有名称空间的限制,正适合您所描述的问题。
在Clojure中,准引用和名称空间解析混合在单个功能中。这对于在Clojure这样的语言中编写宏有很大的好处,因为Clojure是“Lisp-1”(与Common Lisp不同,后者具有函数和变量的单独名称空间)。
我也同意,最好不要混淆这些特性,但这会使Clojure中宏的编写不太优雅,所以我可以看出为什么它的工作方式是这样的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接