'(foo bar baz)
- это не ярлык для (list foo bar baz)
, а ярлык для (quote (foo bar baz))
. В то время как версия списка будет возвращать список, содержащий значения переменных foo, bar и baz, версия с '
вернет список, содержащий символы foo, bar и baz. (Другими словами '(if expr nil body)
совпадает с (list 'if 'expr 'nil 'body)
.
Это приводит к ошибке, потому что в указанной версии макрос расширяется до (if expr nil body)
вместо (if (= 1 2) nil (println "Yo"))
(потому что вместо замены аргументов макроса для expr и body он просто возвращает имя expr и body (которые затем рассматривается как несуществующие переменные в расширенном коде).
Ярлык, который полезен в определениях макросов, использует `
. `
работает так же, как '
(т. Е. Цитирует выражение, следующее за ним), но позволяет вычислять некоторые подвыражения без кавычек, используя ~
. Например, ваш макрос может быть переписан как (defmacro unless [expr body] `(if ~expr nil ~body))
. Здесь важно то, что expr
и body
без кавычек с ~
. Таким образом, расширение будет содержать их значения вместо буквальных имен expr
и body
.