Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лахов.doc
Скачиваний:
1
Добавлен:
15.04.2019
Размер:
380.42 Кб
Скачать

Макрос не вычисляет аргументы

Синтаксис определения макроса выглядит также, как синтаксис используемый при определении функций формы DEFUN:

(DEFMACRO имя лямбда- список тело)

Вызов макроса совпадает по форме с вызовом функции, но его вычисление отличается от вычисления вызова функции. Первое отличие состоит в том, что в макросе не вычисляются аргументы. Тело макроса вычисляется с аргументами в том виде, как они записаны.

Макрос вычисляется дважды

Второе отличие макроса от функции связано со способом вычисления тела макроса. Вычисление вызова макроса состоит из двух последовательных этапов.

На первом этапе осуществляется вычисление тела определения с аргументами из вызова таким же образом, как и для функции. Этот этап называют этапом расширения (expansion) или раскрытия макроса, поскольку возникающая форма, как правило, больше и сложнее исходный формат вызова.

Определим, например, макрос SETQQ, который действует наподобие SETQ, но блокирует вычисление и второго своего аргумента:

_(defmacro setqq (x y)

(list’ setq x (list ’quote y)))

SETQQ

_(setqq spisok(a b c))

(А В С)

;SETQQ не вычисляет свои аргументы

spisok

_(А В С)

После этапа расширения макровызова значением тела макроса было:

(SETQ spisok(QUOTE (А В С)))

на втором этапе эта программно созданная форма вычисляется обычным образом и ее значение возвращаются в качестве значения вызова макроса. В этом случае у возникшей формы есть побочный эффект.

Итак, макрос- эта форма, которая во время вычисления заменяется на новую, обычно более сложную форму, которая затем вычисляется обычным образом.

Контекст вычисления макроса

Макросы отличаются от функций и в отношение контекста вычислений. В этом смысле этап расширения макроса аналогичен вычислению функции, а этап последующего вычисления - нет. Во время расширения макроса доступны синтаксические связи из контекста определения. Вычисление же полученной в результате расширения формы производится вне контекста макровызова, и поэтому статические связи из макроса не действуют. Следовательно, содержащее макровызов выражение эквивалентно выражению, в котором вызов заменен на его расширенную форму.

Пример отличия макроса от макроса

В качестве примера отличий функций и макросов в Коммон ЛИСПе рассмотрим операцию добавления элемента в стек, называемую PUSH, запрограммированную сначала обычными средствами, а потом по средствам макроса. Пользователь применяет PUSH следующим образом:

(PUSH элемент стек)

Вызов PUSH добавлял бы в начале списка, являющегося значением переменной стека стек новый элемент-элемент обновляя значение переменной соответствующим образом:

_(setq stek ’(b c))

(B C)

_(push ‘а stek)

(А В С)

_stek

(А В С)

Определим форму PUSH сначала как функцию:

_(defun pushl (a p)

(setq p (cons a (eval p))))

PUSH 1

_(setq stek ‘(b c))

(B C)

_(push1 ‘a ‘stek) ; имя стека с апострофом

(А В С)

_ stek

(А В С)

Используем макрос:

_(defmacro push2 (a p)

(list ‘setq p (list ‘cons a p)))

PUSH2

Апостроф при передаче стека теперь не нужны, поскольку макровызовов не вычисляет аргументы, а формы, являющиеся аргументами, связываются с формальными параметрами в том виде, как они записаны. При вычислении вызова значением параметра А будет (QUOTE A), значением параметра Р-Р из вызова. В качестве макрорасширения тела макроса будет получено выражение:

( SETQ P (CONS (QUOTE A) P))