clojure 的语法引用是如何工作的? [英] How does clojure's syntax-quote work?

查看:18
本文介绍了clojure 的语法引用是如何工作的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Various special characters in clojure are abbreviations for things

(quote (a b)) 等同于 '(a b)

通过评估可以看出:

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

这似乎是缩写的语法,我觉得这是个好主意.

This seems to be syntax as abbreviation, which strikes me as a fine idea.

但是语法引号 ` 似乎很特别.我想不出什么等同于

But the syntax-quote, ` , seems special. I can't think what would be equivalent to

`(a b)

我会猜到诸如 (syntax-quote (ab)) 之类的东西,但它不起作用,如果我只是猜错了,我就无法找出它的真正含义叫.

I would have guessed something like (syntax-quote (a b)) , but it doesn't work, and if I've just guessed wrong, I can't find out what it's really called.

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

有点神秘.

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

Presumably the reader's doing something special, maybe because it needs to know the namespaces?

有趣的是,语法引用中使用的特殊语法确实按我的预期工作:

Interestingly, the special syntax used in the syntax-quote does work as I expected:

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"))

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

I do realise that I'm being a bit feeble here, and should just go and read the code. If no-one fancies explaining what's going on or giving a reference, can anyone give me a hint about how to find the relevant code and what to look for?

推荐答案

我认为没有与 quote 函数等效的语法引用.

I don't think there's a syntax-quote equivalent of the quote function.

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

The Clojure reader is (currently) written in Java. The SyntaxQuoteReader class in src/jvm/clojure/lang/LispReader.java in the Clojure source is probably what you'll want to read. It seems rather complex. You can see it building lists like (seq (concat ...)) there.

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

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

It's common for the reader not to return straightforward Clojure code, but rather do the right thing in Java-land immediately. For example '[1 2 3] doesn't yield the Clojure code (vector 1 2 3). Maybe it could work that way somehow, but it doesn't. The reader just creates and returns the vector object itself.

同样,SyntaxQuoteReader 立即在 Java 中执行一些魔术来解析符号命名空间并创建 gensym 本身,它返回一些错误且看起来复杂的 Clojure 代码,这些代码可以做正确的事情,但不一定易于人类阅读.是因为必须如此,还是因为在 Java 中这样做更容易,或者出于性能或其他原因,我不知道.同样,我不知道 quasiquote 是否可以作为 Clojure 中的普通宏/特殊形式存在并且不存在,或者它根本不存在.我不明白为什么它不能.

Likewise, the SyntaxQuoteReader does some magic in Java immediately to resolve symbol namespaces and create gensyms itself and it returns some mangled and complicated-looking Clojure code that does the right thing, but isn't necessarily easy for a human to read. Whether it's like this because it has to be, or because it's easier to do it this way in Java, or for performance or some other reason, I don't know. Likewise I don't know if quasiquote could exist as a plain macro/special form in Clojure and doesn't, or if it couldn't exist at all. I don't see why it couldn't though.

WrappingReader 是处理 '(普通的旧 quote)的类.您可以看到它只是将您传递给它的任何内容包装在一个包含符号 quote 和您的参数的列表中.这要简单得多.注意这个类也处理@,所以'@foo确实返回(deref foo).

WrappingReader in the same file is the class that handles ' (plain old quote). You can see that it just wraps whatever you pass it in a list containing the symbol quote plus your argument. It's much simpler. Note that this class also handles @, so that '@foo does return (deref foo).

这个话题可能会更清晰.

这是一个概念验证 quasiquote 宏.请注意,此代码以一种可怕的方式依赖并滥用了 Clojure 内部结构.请不要将其用于任何用途.

Here's a proof-of-concept quasiquote macro. Note that this code is relying upon and abusing Clojure internals in a horrible way. Please don't use this for anything.

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)

这篇关于clojure 的语法引用是如何工作的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆