8.2 Раскрытие макроса

Функция macroexpand служит для раскрытия макровызовов. Также предоставляется ловушка для пользовательской функции для управления процессом раскрытия.

[Функция] macroexpand form &optional env
[Функция] macroexpand-1 form &optional env

Если форма form является макровызовом, тогда macroexpand-1 раскроет макровызов только на один уровень и вернёт два значения: раскрытие и t. Если форма form не является макровызовом, тогда будут возвращены два значения: form и nil.

Форма form рассматривается как макровызов, только если она является cons-ячейкой, у которой car элемент является символом имени макроса. Окружение env похоже на то, что используется внутри вычислителя (смотрите evalhook). По-умолчанию равно нулевому окружению. Если окружение указано будут рассмотрены все установленные внутри env с помощью macrolet локальные определения макросов. Если в качестве аргумента указана только форма form, то берётся нулевое окружение, и будут рассматриваться только глобальные определения макросов (установленные с помощью defmacro).

Раскрытие макросов происходит следующим образом. Когда macroexpand-1 устанавливает, что символ в форме указывает на макрос, тогда она получает функцию раскрытия для этого макроса. Затем вызывается значение переменной *macroexpand-hook*, как функция трёх аргументов с параметрами: функция раскрытия, форма form и окружение env. Значение, возвращённое этим вызовом, расценивается, как раскрытие макровызова. Значение переменной *macroexpand-hook* по-умолчанию funcall, которая следовательно просто запускает функцию раскрытия с двумя параметрами: формой form и окружением env.

X3J13 voted in June 1988 to specify that the value of *macroexpand-hook* is first coerced to a function before being called as the expansion interface hook. Therefore its value may be a symbol, a lambda-expression, or any object of type function.

X3J13 voted in March 1989 to specify that macro environment objects received by a *macroexpand-hook* function have only dynamic extent. The consequences are undefined if such objects are referred to outside the dynamic extent of that particular invocation of the hook function. This allows implementations to use somewhat more efficient techniques for representing environment objects.

X3J13 voted in June 1989 to clarify that, while *macroexpand-hook* may be useful for debugging purposes, despite the original design intent there is currently no correct portable way to use it for caching macro expansions.

X3J13 also noted that, although there seems to be no correct portable way to use *macroexpand-hook* to cache macro expansions, there is no requirement that an implementation call the macro expansion function more than once for a given form and lexical environment.

X3J13 voted in March 1989 to specify that macroexpand-1 will also expand symbol macros defined by symbol-macrolet; therefore a form may also be a macro call if it is a symbol. The vote did not address the interaction of this feature with the *macroexpand-hook* function. An obvious implementation choice is that the hook function is indeed called and given a special expansion function that, when applied to the form (a symbol) and env, will produce the expansion, just as for an ordinary macro; but this is only my suggestion.

Вычислитель раскрывает макровызовы, как если бы использовал macroexpand-1. Таким образом eval также использует *macroexpand-hook*.

macroexpand похожа на macroexpand-1, однако циклично раскрывает форму form, пока в ней не останется макровызовов. (А точнее, macroexpand просто циклично вызывает macroexpand-1, пока последняя не вернёт nil во втором значении.) Второе возвращаемое значение функции macroexpand-1 (t или nil) указывает на то, являлась ли форма form макровызовом.


[Переменная] *macroexpand-hook*

Значение *macroexpand-hook* используется как интерфейс раскрытия для macroexpand-1.