14.3 Макросы и байт-компиляция

Вы можете спросить, зачем мы тратим усилия на вычисление развертывания для макроса, а затем вычисляем это развертывание. Почему бы не заставить тело макроса производить желаемые результаты напрямую? Причина связана с компиляцией.

Когда в Lisp-программе, которая компилируется, появляется вызов макроса, компилятор Lisp вызывает определение макроса так же, как это сделал бы интерпретатор, и получает развертывание. Но вместо вычисления этого развертывания он компилирует его так, как если бы оно появилось напрямую в программе. В результате скомпилированный код производит значение и побочные эффекты, предусмотренные для макроса, но выполняется с полной скоростью компилированного кода. Это не сработало бы, если бы тело макроса вычисляло значение и побочные эффекты само — они были бы вычислены во время компиляции, что не полезно.

Чтобы компиляция вызовов макросов работала, макросы должны быть уже определены в Lisp, когда компилируются вызовы к ним. Компилятор имеет специальную функцию, чтобы помочь вам в этом: если файл, который компилируется, содержит форму defmacro, макрос временно определяется для остальной части компиляции этого файла.

Байт-компиляция файла также выполняет любые вызовы require на верхнем уровне файла, поэтому вы можете гарантировать, что необходимые определения макросов доступны во время компиляции, требуя файлы, которые их определяют (см. Функции). Чтобы избежать загрузки файлов определений макросов, когда кто-то запускает скомпилированную программу, используйте eval-when-compile вокруг вызовов require (см. Вычисление во время компиляции).