Spec-Zone.ru › Elisp

Сколько раз макрос расширяется?

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

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

Один особый вид побочных эффектов избежать нельзя: построение объектов Lisp. Почти все расширения макросов включают построенные списки; это основная цель большинства макросов. Обычно это безопасно; есть только один случай, когда нужно быть осторожным: когда создаваемый вами объект является частью цитируемой константы в расширении макроса.

Если макрос расширяется только один раз во время компиляции, то объект создается только один раз во время компиляции. Но при интерпретированном выполнении макрос расширяется каждый раз, когда вызывается вызов макроса, а это означает, что каждый раз создается новый объект.

В большинстве чистого кода Lisp эта разница не имеет значения. Она может иметь значение только если вы выполняете побочные эффекты над объектами, созданными определением макроса. Таким образом, чтобы избежать проблем, избегайте побочных эффектов над объектами, созданными определениями макросов. Вот пример того, как такие побочные эффекты могут привести к проблемам:

(defmacro empty-object ()
  (list 'quote (cons nil nil)))
(defun initialize (condition)
  (let ((object (empty-object)))
    (if condition
        (setcar object condition))
    object))

Если initialize интерпретируется, новый список (nil) создается каждый раз, когда вызывается initialize. Таким образом, никакие побочные эффекты не сохраняются между вызовами. Если initialize компилируется, тогда макрос empty-object расширяется во время компиляции, создавая одну константу (nil), которая повторно используется и изменяется каждый раз, когда вызывается initialize.

Один из способов избежать патологических случаев, подобных этому, — рассматривать empty-object как своеобразную константу, а не как конструкцию выделения памяти. Вы не использовали бы setcar с константой, такой как '(nil), поэтому естественно, вы не будете использовать её и с (empty-object).

Copyright © 1990-1996, 1998-2022 Free Software Foundation, Inc.
Licensed under the GNU GPL license.
https://www.gnu.org/software/emacs/manual/html_node/elisp/Repeated-Expansion.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API