Eval-когда использует?

Прочитав много документации относительно Лиспeval-when оператор Я до сих пор не могу понять его использование, я знаю, что с помощью этого оператора я могу контролировать время оценки своих выражений, но я не могу найти какой-либо пример, где это может быть применимо?

С уважением, utxeee.

Ответы на вопрос(1)

Решение Вопроса

Compilation of a Lisp file

Возьмем для примера компиляцию файла Lisp. Компилятор Lisp обрабатывает формы верхнего уровня. Это могут быть произвольные формы Lisp, DEFUN, DEFMACROS, DEFCLASS, вызовы функций, ...

Вся история о том, как работает файловый компилятор, слишком сложна, чтобы объяснить здесь, но несколько вещей:

the file compiler generates code for a (DEFUN foo () ) form. But it does not execute the defun form. Thus during compilation it is known that there is a function FOO, but the code of ˋFOOˋ is not available during the compilation. The compiler generates the code for the compiled file, but does not keep it in memory. You can't call such a function at compile time.

for macros this works slightly different: (DEFMACRO BAZ ...). The file compiler will not only compile the macro and note that it is there, but it will also make the macro available at compilation time. It is loaded into the compiler environment.

Таким образом представьте последовательность форм в файле:

(defmacro baz ...)

(defun foo () (baz ...))

Это работает, потому что файловый компилятор знает макросBAZ и когда он компилирует код дляFOOзатем он может расширить форму макроса.

Теперь давайте посмотрим на следующий пример:

(defun bar (form) ...)

(defmacro baz (form) (bar form))

(defun foo () (baz ...))

Выше не будет работать. Теперь макросBAZ использует функциюBAR позвонив Когда компилятор пытается скомпилировать функциюFOOне может расширитьBAZ макрос, потому чтоBAR не может быть вызван, потому что кодBAR не загружается в среду компиляции.

Есть два решения этого:

compile and load BAR earlier using a separate file. Use EVAL-WHEN

Пример дляEVAL-WHEN:

 (eval-when (:compile-toplevel :execute :load-toplevel)
   (defun bar (form) ...)
 )

 (defmacro baz (form) (bar form))

 (defun foo () (baz ...))

ТеперьEVAL-WHEN инструктирует файловый компилятор фактически запускать форму DEFUN во время компиляции. Эффект этого таков: файловый компилятор теперь знает определениеBAR вcompile time, Таким образом, это доступно позже, когда файловый компилятор должен вызватьBAR во время расширения макроса использованияBAZ.

Можно было использовать только:compile-toplevel, когда функция не понадобится после компиляции файла. Если он используется позже, то нам нужно убедиться, что он загружен.

ТакEVAL-WHEN позволяет указать, следует ли запускать определенный фрагмент кода

during compilation of a file during loading of a file during execution

EVAL-WHEN часто используется в коде пользователя. Если вы используете его, то вы должны спросить себя, действительно ли вам это нужно.

 utxeee21 мая 2012 г., 15:20
Райнер, еще два вопроса: (1) - если мы загрузили файл из исходного кода с вашим примером, то не было необходимости использовать оператор eval-when, потому что определение бара уже известно, верно? (2) - Почему нам нужно использовать ключевое слово: execute - насколько я знаю, это ключевое слово связано со временем выполнения, но во время выполнения определение функции уже известно, верно?
 utxeee20 мая 2012 г., 21:16
Привет, Райнер, но почему мы должны использовать флаги: execute и: load-top-level в этом использовании eval-when?
 21 мая 2012 г., 12:37
@utxeee: load-top-level является значением по умолчанию во время компиляции, когда EVAL-WHEN отсутствует.
 13 сент. 2015 г., 20:56
не могли бы вы исправить опечаткуload-top-level == & GT;:load-toplevel? Я должен был копаться в источнике, чтобы найти это
 utxeee21 мая 2012 г., 01:35
Райнер, еще раз спасибо за ваш ответ, редактирующий предыдущий ответ: D Но мои сомнения остаются, почему мне нужно использовать флаги: load-top-level и: execute. Из вашего текста я вижу, что мы должны использовать флаг: load-top-level, если функция используется позже. Так почему же нам не нужно использовать eval-when с: load-top-level во всех других функциях, которые будут использоваться позже?

Ваш ответ на вопрос