Spec-Zone.ru › Elisp

Лексическое связывание

Лексическое связывание доступно только в современном диалекте Emacs Lisp. (См. Выбор диалекта Lisp.) Переменная с лексической привязкой имеет лексическую область видимости, то есть любое обращение к переменной должно находиться текстуально внутри конструкции связывания. Вот пример

(let ((x 1))    ; x is lexically bound.
  (+ x 3))
     ⇒ 4

(defun getx ()
  x)            ; x is used free in this function.

(let ((x 1))    ; x is lexically bound.
  (getx))
error→ Symbol's value as variable is void: x

Здесь у переменной x нет глобального значения. При лексическом связывании внутри формы let ее можно использовать в текстовых пределах этой формы let. Но ее нельзя использовать из функции getx, вызванной из формы let, поскольку определение функции getx находится вне самой формы let.

Вот как работает лексическое связывание. Каждая конструкция связывания задает лексическое окружение, определяющее переменные, связанные внутри конструкции, и их локальные значения. Когда интерпретатор Lisp запрашивает текущее значение переменной, он сначала ищет его в лексическом окружении; если переменная там не указана, он обращается к ячейке значения символа, где хранится динамическое значение.

Лексические связывания имеют неограниченное время существования. Даже после завершения выполнения конструкции связывания ее лексическое окружение может «сохраняться» в объектах Lisp, называемых замыканиями. Замыкание создается при определении именованной или анонимной функции с включенным лексическим связыванием. Подробнее см. Замыкания.

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

(defvar my-ticker nil)   ; We will use this dynamically bound
                         ; variable to store a closure.

(let ((x 0))             ; x is lexically bound.
  (setq my-ticker (lambda ()
                    (setq x (1+ x)))))
    ⇒ #f(lambda () [(x 0)]
          (setq x (1+ x)))

(funcall my-ticker)
    ⇒ 1

(funcall my-ticker)
    ⇒ 2

(funcall my-ticker)
    ⇒ 3

x                        ; Note that x has no global value.
error→ Symbol's value as variable is void: x

Здесь связывание let задает лексическое окружение, в котором переменная x локально связана со значением 0. Внутри этой конструкции связывания мы определяем лямбда-выражение, которое увеличивает x на единицу и возвращает увеличенное значение. Это лямбда-выражение автоматически преобразуется в замыкание, в котором лексическое окружение сохраняется и после завершения конструкции связывания let. При каждой оценке замыкания оно увеличивает x, используя связывание x в этом лексическом окружении.

Обратите внимание: в отличие от динамических переменных, связанных с самим объектом-символом, связь между лексическими переменными и символами существует только в интерпретаторе (или компиляторе). Поэтому функции, принимающие символ в качестве аргумента (например, symbol-value, boundp и set), могут только получать или изменять динамическое связывание переменной (то есть содержимое ячейки значения ее символа).

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

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

Spec-Zone.ru

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