Подтвердить что ты не робот

Как работает синтаксическая цитата 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))))

Немного мистифицирует.

Предположительно читатель делает что-то особенное, может быть, потому, что ему нужно знать пространства имен?

Интересно, что специальный синтаксис, используемый в цитате синтаксиса, работает так, как я ожидал:

user> '~a
(clojure.core/unquote a)
user> '[email protected]
(clojure.core/unquote-splicing a)
user> '~'a
(clojure.core/unquote (quote a))

кроме этого:

user> 'a#
a#

Я бы подумал, что это что-то вроде (unquote (gensym "a"))

Я понимаю, что здесь я немного неловкий, и я должен просто пойти и прочитать код. Если кто-то не хочет объяснять, что происходит или дает ссылку, может ли кто-нибудь дать мне подсказку о том, как найти соответствующий код и что искать?

4b9b3361

Ответ 1

Я не думаю, что есть эквивалент синтаксиса-кавычки функции quote.

Читатель Clojure (в настоящее время) написан на Java. Класс SyntaxQuoteReader в src/jvm/clojure/lang/LispReader.java в источнике Clojure - это, вероятно, то, что вы хотите прочитать. Это кажется довольно сложным. Вы можете видеть, что там строятся списки, например (seq (concat ...)).

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

Обычно читателю не нужно возвращать простой код Clojure, а делать то, что нужно прямо на Java-земле. Например, '[1 2 3] не дает код Clojure (vector 1 2 3). Может быть, так или иначе, но это не так. Читатель просто создает и возвращает сам векторный объект.

Аналогично, SyntaxQuoteReader делает некоторую магию в Java немедленно для разрешения пространств имен символов и создания самих gensyms и возвращает некоторый искаженный и сложный вид кода Clojure, который делает правильные вещи, но не всегда легко для человека читать. Так ли это, потому что это должно быть, или потому, что это проще сделать на Java, или для производительности, или по какой-то другой причине, я не знаю. Аналогично, я не знаю, может ли quasiquote существовать как простой макрос/специальная форма в Clojure и не существует, или вообще не может существовать. Я не понимаю, почему это не могло быть.

WrappingReader в том же файле находится класс, который обрабатывает ' (обычный старый quote). Вы можете видеть, что он просто переносит все, что вы передаете, в список, содержащий символ quote плюс ваш аргумент. Это намного проще. Обратите внимание, что этот класс также обрабатывает @, так что '@foo возвращает (deref foo).

Этот поток может пролить немного света.

Изменить

Здесь макрос макросов 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)

Ответ 2

Похоже, вы прекрасно разбираетесь в синтаксисе макросов, поэтому я не могу добавить слишком много.

есть немного охвата на программировании clojure форумов. и вы можете на своем месте читать здесь код проверить строку 352

Ответ 3

hiredman внедрил полностью clojure версию синтаксиса-цитаты. Не для слабонервных, а для хорошего доказательства концепции.