Что подразумевается при добавлении в качестве префикса переменной в макросе

Учитывая макрос ниже -

(defmacro defhello [fn-name body]   `(defn ~fn-name [~'name] ~body))

и функция, определенная при вызове как -

(defhello приветствие (имя "Hello" ))

и называется

(приветствие "Джо" )

вернет

Hello Joe

Я не понимаю использование ~ 'перед параметром имени? Что оно делает? Не процитировать (') и unquote (~) отменить друг друга? Что происходит, когда они используются вместе? Почему бы просто написать имя без них?

Ответ 1

Короче говоря, ~ оценивает выражение в форме с синтаксисом, как и для ~fn-name. В этом случае выражение для оценки равно 'name, в котором результатом является неквалифицированный символ name.

Однако, давайте сломаем это по одной части за раз.

Если у вас был только неквалифицированный символ name, он был бы оценен как clojure.core/name во время выполнения 1. Это приведет к неправильной форме defn и вызовет исключение компилятора.

(defn greeting [clojure.core/name] (str "Hello" name)) 

Если у вас был только неквалифицированный символ 'name, он все равно будет оцениваться во время выполнения. Разница в том, что она будет расширяться до (quote clojure.core/name). Опять же, это приведет к неправильной форме defn и вызовет исключение компилятора.

(defn greeting [(quote clojure.core/name)] (str "Hello" name))

Наконец, используя ~'name, вы будете иметь котировальную форму, полученную во время компиляции, в результате получится неквалифицированный символ name, оставив вам правильную форму defn.

(defn greeting [name] (str "Hello" name))

1 - Это верно для этого примера, потому что предполагается, что еще одна функция name не существует.

Ответ 2

Как я понимаю, вы приводите определение функции, поэтому оно не будет оцениваться при определении макроса. Вы используете оператор unquote ~, чтобы оценить имя в определении. Если имя было своего рода списком [email protected] (unquote splice), он будет оценивать элементы списка без окружающих скобок.

Ответ 3

Цитата перед именем используется для сохранения символа от квалификации.

Если вы не знаете, что такое квалификация, обратитесь к Reader.

Кроме того, вы можете использовать macroexpand для отладки макросов.

И если вы хотите узнать больше о макросах, я рекомендую вам прочитать Вкл Lisp. Может быть, это немного сложно, но это позволит вам знать, как работает макрос.