clojure的语法引用如何工作?

时间:2010-09-13 20:58:56

标签: clojure

clojure中的各种特殊字符是事物的缩写

(quote (a b))'(a b)

相同

通过评估可以看出:

user> ''(a b)
(quote (a b))

这似乎是语法缩写,这让我觉得很好。

但是语法引用`似乎很特别。我想不出什么相当于

`(a b)

我会猜到像(syntax-quote (a b))这样的东西,但它不起作用,如果我猜错了,我就找不到它真正叫做的东西。

user> '`(a b)
(clojure.core/seq (clojure.core/concat (clojure.core/list (quote user/a)) (clojure.core/list (quote user/b))))

有点神秘。

大概是读者做了一些特别的事情,也许是因为它需要知道命名空间?

有趣的是,syntax-quote中使用的特殊语法确实可以正常工作:

user> '~a
(clojure.core/unquote a)
user> '~@a
(clojure.core/unquote-splicing a)
user> '~'a
(clojure.core/unquote (quote a))

除了这一个:

user> 'a#
a#

我想到的是(unquote (gensym "a"))

之类的东西

我确实意识到我在这里有点虚弱,应该去阅读代码。如果没有人想解释正在发生的事情或提供参考,那么任何人都可以给我一个关于如何找到相关代码以及寻找什么的提示吗?

3 个答案:

答案 0 :(得分:33)

我不认为语法引用等同于quote函数。

Clojure读者(目前)是用Java编写的。 Clojure源代码中SyntaxQuoteReader中的src/jvm/clojure/lang/LispReader.java类可能是您想要阅读的内容。看起来相当复杂。您可以看到它构建了(seq (concat ...))那样的列表。

                ret = RT.list(SEQ, RT.cons(CONCAT, sqExpandList(seq)));

读者通常不会返回简单的Clojure代码,而是立即在Java-land中做正确的事情。例如,'[1 2 3]不会产生Clojure代码(vector 1 2 3)。也许它可以以某种方式工作,但事实并非如此。读者只需创建并返回矢量对象本身。

同样地,SyntaxQuoteReader在Java中立即起到了解决符号命名空间和创建gensyms的神奇作用,并且它返回了一些错误且复杂的Clojure代码,它做了正确的事情,但不一定容易人类阅读。无论是因为它必须是这样,还是因为在Java中这样做更容易,或者出于性能或其他原因,我不知道。同样地,我不知道quasiquote是否可以作为Clojure中的普通宏/特殊形式存在而不存在,或者它是否根本不存在。我不明白为什么它不能。但

同一文件中的

WrappingReader是处理'(普通旧quote)的类。您可以看到它只包含您在包含符号quote加上您的参数的列表中传递的任何内容。它简单得多。请注意,此类还会处理@,以便'@foo返回(deref foo)

This thread可能会有更多的亮点。

修改

这是一个概念验证quasiquote宏。请注意,此代码以可怕的方式依赖和滥用Clojure内部。请不要将它用于任何事情。

user> (defmacro quasiquote [x]
        (let [m (.getDeclaredMethod clojure.lang.LispReader$SyntaxQuoteReader 
                                    "syntaxQuote" 
                                    (into-array [Object]))]
          (.setAccessible m true)
          (.invoke m nil (into-array [x]))))
#'user/quasiquote
user> (let [x 123] `(x 'x ~x))
(user/x (quote user/x) 123)
user> (let [x 123] (quasiquote (x 'x ~x)))
(user/x (quote user/x) 123)

答案 1 :(得分:3)

您似乎非常了解宏语法,因此我可以添加太多内容。

programming clojure forums上有一点报道。 你可以随便阅读code here结帐第352行

答案 2 :(得分:3)

hiredman已经实现了基于完全基于clojure的syntax-quote版本。不是为了胆小的人,而是一个很好的概念证明。