Ответ 1
'(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
.