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

Какова цель ~ 'или' ~ в Clojure?

Я изучаю макросы Clojure, а примеры кода иногда имеют конструкции '~symbol или попеременно ~'symbol. Я знаю, что (quote и ' препятствуют оценке формы и что backquote дополнительно добавляет квалификацию пространства имен и что ~ вызывает оценку кавычки. Мой вопрос: почему полезно остановиться, а затем начать оценку? Я также предполагаю, что ~'symbol и '~symbol различны, но как это?

4b9b3361

Ответ 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, потому что у меня нет синтаксиса-кавычки