Вызов макроса выглядит точно так же, как вызов функции: это список, который начинается с имени макроса. Остальные элементы списка — это аргументы макроса.
Выполнение вызова макроса начинается, как и выполнение вызова функции, за исключением одного критического различия: аргументы макроса — это фактические выражения, присутствующие в вызове макроса. Они не вычисляются до того, как передаются в определение макроса. В отличие от этого, аргументы функции являются результатом вычисления элементов списка вызова функции.
Получив аргументы, Lisp вызывает определение макроса точно так же, как вызывается тело функции. Переменные аргументов макроса связываются с значениями аргументов из вызова макроса или со списком этих значений в случае аргумента &rest. И тело макроса выполняется и возвращает свое значение точно так же, как тело функции.
Второе критическое различие между макросами и функциями заключается в том, что значение, возвращаемое телом макроса, является альтернативным выражением Lisp, также известным как расширение макроса. Интерпретатор Lisp продолжает вычислять это расширение, как только он возвращается из макроса.
Поскольку расширение вычисляется обычным образом, оно может содержать вызовы других макросов. Оно даже может быть вызовом того же самого макроса, хотя это необычно.
Обратите внимание, что Emacs пытается расширить макросы при загрузке нескомпилированного файла Lisp. Это не всегда возможно, но если это происходит, это ускоряет последующее выполнение. См. Как программы загружаются.
Вы можете увидеть расширение заданного вызова макроса, вызвав macroexpand.
Эта функция расширяет form, если это вызов макроса. Если результат — это еще один вызов макроса, он расширяется по очереди, пока не будет получен результат, который не является вызовом макроса. Это и есть значение, возвращаемое macroexpand. Если form изначально не является вызовом макроса, он возвращается без изменений.
Обратите внимание, что macroexpand не рассматривает подвыражения form (хотя некоторые определения макросов могут это делать). Даже если они сами являются вызовами макросов, macroexpand их не расширяет.
Функция macroexpand не расширяет вызовы встроенных функций. Обычно для этого нет необходимости, поскольку вызов встроенной функции не сложнее для понимания, чем вызов обычной функции.
Если предоставлен environment, он указывает список определений макросов, которые переопределяют текущие определенные макросы. Компиляция байт-кода использует эту функцию.
(defmacro inc (var)
(list 'setq var (list '1+ var)))
(macroexpand '(inc r))
⇒ (setq r (1+ r))
(defmacro inc2 (var1 var2)
(list 'progn (list 'inc var1) (list 'inc var2)))
(macroexpand '(inc2 r s))
⇒ (progn (inc r) (inc s)) ; inc не расширен здесь.
macroexpand-all расширяет макросы, как macroexpand, но ищет и расширяет все макросы в form, а не только на верхнем уровне. Если макросы не расширяются, возвращаемое значение равно eq form.
Повторяя пример, использованный для macroexpand выше, с macroexpand-all мы видим, что macroexpand-all расширяет вложенные вызовы inc:
(macroexpand-all '(inc2 r s))
⇒ (progn (setq r (1+ r)) (setq s (1+ s)))
Эта функция расширяет макросы, как macroexpand, но выполняет только один шаг расширения: если результат — это еще один вызов макроса, macroexpand-1 его не расширяет.