10.5 Eval

Чаще всего формы оцениваются автоматически, благодаря их появлению в выполняемой программе. В редких случаях вам может потребоваться написать код, который оценивает форму, вычисляемую во время выполнения, например, после чтения формы из редактируемого текста или получения ее из списка свойств. В таких случаях используйте функцию eval. Часто eval не нужен, и вместо него следует использовать что-то другое. Например, чтобы получить значение переменной, хотя eval работает, предпочтительнее использовать symbol-value; или вместо того, чтобы хранить выражения в списке свойств, которые затем должны пройти через eval, лучше хранить функции, которые затем передаются в funcall.

Функции и переменные, описанные в этом разделе, оценивают формы, указывают пределы процесса оценки или записывают недавно возвращенные значения. Загрузка файла также выполняет оценку (см. Загрузка).

Как правило, чище и гибче хранить функцию в структуре данных и вызывать ее с помощью funcall или apply, чем хранить выражение в структуре данных и оценивать его. Использование функций дает возможность передавать им информацию в качестве аргументов.

Функция: eval form &optional lexical

Это базовая функция для оценки выражения. Она оценивает form в текущей среде и возвращает результат. Тип объекта form определяет, как он оценивается. См. Виды форм.

Аргумент lexical указывает правило области видимости для локальных переменных (см. Правила области видимости для привязок переменных). Если он равен t, это означает оценку form с использованием лексической области видимости; это рекомендуемое значение. Если он опущен или равен nil, это означает использование старого правила динамической области видимости переменных.

Значение lexical также может быть непустым списком, указывающим на определенную лексическую среду для лексических привязок; однако эта функция полезна только для специализированных целей, например, в отладчиках Emacs Lisp. Каждый элемент списка — это либо ячейка cons, представляющая пару лексическое имя-значение, либо символ, представляющий (специальную) переменную, которая использовала бы динамическую область видимости, если бы была привязана.

Поскольку eval является функцией, аргументное выражение, появляющееся в вызове eval, оценивается дважды: один раз в качестве подготовки перед вызовом eval и еще раз самой функцией eval. Вот пример:

(setq foo 'bar)
     ⇒ bar
(setq bar 'baz)
     ⇒ baz
;; Здесь eval получает аргумент foo
(eval 'foo)
     ⇒ bar
;; Здесь eval получает аргумент bar, который является значением foo
(eval foo)
     ⇒ baz

Количество одновременно активных вызовов eval ограничено max-lisp-eval-depth (см. ниже).

Команда: eval-region start end &optional stream read-function

Эта функция оценивает формы в текущем буфере в области, определенной позициями start и end. Она считывает формы из области и вызывает eval для них до достижения конца области или до сигнализации ошибки и ее необработки.

По умолчанию eval-region не выводит никакого вывода. Однако, если stream не равен nil, любой вывод, генерируемый функциями вывода (см. Функции вывода), а также значения, полученные в результате оценки выражений в области, печатаются с использованием stream. См. Потоки вывода.

Если read-function не равен nil, это должна быть функция, которая используется вместо read для поочередного считывания выражений. Эта функция вызывается с одним аргументом — потоком для считывания ввода. Вы также можете использовать переменную load-read-function (см. Как программы загружаются) для указания этой функции, но более надежно использовать аргумент read-function.

eval-region не перемещает курсор. Она всегда возвращает nil.

Команда: eval-buffer &optional buffer-or-name stream filename unibyte print

Это похоже на eval-region, но аргументы предоставляют различные необязательные возможности. eval-buffer работает со всем доступным участком буфера buffer-or-name (см. Ограничение в Справочник GNU Emacs). buffer-or-name может быть буфером, именем буфера (строкой) или nil (или опущен), что означает использование текущего буфера. stream используется так же, как в eval-region, если stream не равен nil и print не равен nil. В этом случае значения, полученные в результате оценки выражений, все равно отбрасываются, но вывод функций вывода печатается в области эхо. filename — это имя файла, используемое для load-history (см. Выгрузка), и по умолчанию равно buffer-file-name (см. Имя файла буфера). Если unibyte не равен nil, read преобразует строки в unibyte, когда это возможно.

Пользовательская опция: max-lisp-eval-depth

Эта переменная определяет максимальную глубину, разрешенную в вызовах eval, apply и funcall, прежде чем будет сигнализирована ошибка (с сообщением об ошибке "Lisp nesting exceeds max-lisp-eval-depth").

Этот лимит, с связанной с ним ошибкой при его превышении, — это то, как Emacs Lisp избегает бесконечной рекурсии в плохо определенной функции. Если вы слишком сильно увеличите значение max-lisp-eval-depth, такой код может вызвать переполнение стека вместо этого. В некоторых системах это переполнение может обрабатываться. В этом случае нормальная оценка Lisp прерывается, и управление передается обратно в главный цикл команд (top-level). Обратите внимание, что в этой ситуации невозможно войти в отладчик Emacs Lisp. См. Вход в отладчик при ошибке.

Лимит глубины учитывает внутреннее использование eval, apply и funcall, например, для вызова функций, упомянутых в выражениях Lisp, и рекурсивную оценку аргументов вызова функции и форм тела функции, а также явные вызовы в коде Lisp.

Значение по умолчанию этой переменной равно 1600. Если вы установите его в значение меньше 100, Lisp сбросит его до 100, если достигнуто заданное значение.

Пользовательская опция: lisp-eval-depth-reserve

Чтобы иметь возможность отлаживать ошибки бесконечной рекурсии, при вызове отладчика Lisp Emacs временно увеличивает значение max-lisp-eval-depth, если остается мало места, чтобы гарантировать, что сам отладчик имеет место для выполнения. То же самое происходит при выполнении обработчика handler-bind. См. Написание кода для обработки ошибок.

Переменная lisp-eval-depth-reserve ограничивает дополнительную глубину, которую Emacs может добавить к max-lisp-eval-depth в этих исключительных обстоятельствах.

Значение по умолчанию этой переменной равно 200.

Переменная: values

Значение этой переменной — это список значений, возвращенных всеми выражениями, которые были прочитаны, оценены и напечатаны из буферов (включая минибуфер) стандартными командами Emacs, выполняющими это. (Обратите внимание, что это не включает оценку в буферах *ielm*, а также оценку с использованием C-j, C-x C-e и аналогичных команд оценки в lisp-interaction-mode.)

Эта переменная устарела и будет удалена в будущей версии, поскольку она постоянно увеличивает объем памяти процесса Emacs. По этой причине мы не рекомендуем ее использовать.

Элементы values упорядочены от самого недавнего.

(setq x 1)
     ⇒ 1
(list 'A (1+ 2) auto-save-default)
     ⇒ (A 3 t)
values
     ⇒ ((A 3 t) 1 …)

Эта переменная может быть полезна для обращения к значениям недавно оцененных форм. Как правило, плохая идея печатать само значение values, поскольку оно может быть очень длинным. Вместо этого изучите отдельные элементы, например:

;; Обратиться к самому недавнему результату оценки.
(nth 0 values)
     ⇒ (A 3 t)
;; Поэтому новый элемент был добавлен,
;;   поэтому все элементы сдвигаются назад на один.
(nth 1 values)
     ⇒ (A 3 t)
;; Это получает элемент, который был предпоследним
;;   до этого примера.
(nth 3 values)
     ⇒ 1