Я изучаю макросы Clojure, а примеры кода иногда имеют конструкции '~symbol
или попеременно ~'symbol
. Я знаю, что (quote
и '
препятствуют оценке формы и что backquote дополнительно добавляет квалификацию пространства имен и что ~ вызывает оценку кавычки. Мой вопрос: почему полезно остановиться, а затем начать оценку? Я также предполагаю, что ~'symbol
и '~symbol
различны, но как это?
Какова цель ~ 'или' ~ в Clojure?
Ответ 1
~'symbol
используется для создания неквалифицированного символа. Clojure пространство имен для захвата макросов по умолчанию, поэтому символ в макросе обычно будет разрешен до (your-namespace/symbol)
. Идиома без кавычек напрямую приводит к простому, неквалифицированному имени символа - (symbol)
- путем оценки цитируемого символа. Из Радости Clojure:
(defmacro awhen [expr & body]
`(let [~'it ~expr] ; refer to the expression as "it" inside the body
(when ~'it
(do [email protected]))))
(awhen [:a :b :c] (second it)) ; :b
'~symbol
, вероятно, используется для вставки имени в макрос или что-то подобное. Здесь symbol
будет привязано к значению - let [symbol 'my-symbol]
. Это значение затем вставляется в код, который производит макрос, оценивая symbol
.
(defmacro def-symbol-print [sym]
`(defn ~(symbol (str "print-" sym)) []
(println '~sym))) ; print the symbol name passed to the macro
(def-symbol-print foo)
(print-foo) ; foo
Ответ 2
~
- это макрос читателя для функции unquote
. в цитированном списке он вызывает оценку символа, а не как буквенный символ
user> (def unquoted 4)
user>`(this is an ~unquoted list)
(user/this user/is user/an 4 clojure.core/list)
user>
все, кроме символа без кавычек, использовалось точно так же, как символ, где unquoted был разрешен к его значению 4. это чаще всего используется при написании макросов. Repl также печатает пространство имен (пользователя) infront имен при печати итогового списка.
многие макросы, в основном, являются просто шаблонами, предназначенными для создания небольших вариаций на то, что невозможно сделать в функции. В этом надуманном примере макрос шаблона определяет функцию, создавая вызов def. синтаксическая цитата с нечеткой фразой делает это намного проще для чтения:
user> (defmacro def-map-reducer [name mapper reducer]
`(defn ~name [& args#]
(reduce ~reducer (map ~mapper args#))))
#'user/def-map-reducer
user> (def-map-reducer add-incs inc +)
#'user/add-incs
user> (add-incs 1 2 3 4 5)
20
по сравнению с:
user> (defmacro def-map-reducer [name mapper reducer]
(let [args-name (gensym)]
(list `defn name [`& args-name]
(list `reduce reducer (list `map mapper args-name)))))
#'user/def-map-reducer
user> (def-map-reducer add-decs dec +)
#'user/add-decs
user> (add-decs 1 2 3 4 5)
10
user>
во втором примере я также не использую функцию auto-gensyms, потому что у меня нет синтаксиса-кавычки