Лексическое связывание доступно только в современном диалекте Emacs Lisp. (См. Выбор диалекта Lisp.) Переменная с лексическим связыванием имеет лексическую область видимости, что означает, что любая ссылка на переменную должна находиться текстово внутри конструкции связывания. Вот пример
(let ((x 1)) ;xлексически связана. (+ x 3)) ⇒ 4 (defun getx () x) ;xиспользуется свободно в этой функции. (let ((x 1)) ;xлексически связана. (getx)) error→ Значение символа как переменной пусто: x
Здесь переменная x не имеет глобального значения. Когда она лексически
связывается внутри формы let, ее можно использовать в текстовых границах
этой формы let. Но ее нельзя использовать изнутри
функции getx, вызванной из формы let, поскольку
определение функции getx происходит вне самой формы let.
Вот как работает лексическое связывание. Каждая конструкция связывания определяет лексическую среду, указывая переменные, которые связаны внутри конструкции, и их локальные значения. Когда интерпретатор Lisp требует текущее значение переменной, он сначала ищет в лексической среде; если переменная не указана там, он ищет в ячейке значения символа, где хранится динамическое значение.
Лексические связывания имеют неопределенную протяженность. Даже после того, как конструкция связывания завершила выполнение, ее лексическая среда может быть «сохранена» в объектах Lisp, называемых замыканиями. Замыкание создается, когда вы определяете именованную или анонимную функцию с включенным лексическим связыванием. См. Замыкания, для получения подробной информации.
Когда замыкание вызывается как функция, любые лексические ссылки на переменные в его определении используют сохраненную лексическую среду. Вот пример:
(defvar my-ticker nil) ; Мы будем использовать эту динамически связанную ; переменную для хранения замыкания. (let ((x 0)) ;xлексически связана. (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 ; Обратите внимание, чтоxне имеет глобального значения. error→ Значение символа как переменной пусто: x
Здесь связывание let определяет лексическую среду, в которой
переменная x локально связана со значением 0. Внутри этой
конструкции связывания мы определяем лямбда-выражение, которое увеличивает
x на единицу и возвращает увеличенное значение. Это лямбда-выражение
автоматически преобразуется в замыкание, в котором лексическая среда сохраняется
даже после выхода из конструкции связывания let. Каждый раз, когда
мы вычисляем замыкание, оно увеличивает x, используя связывание
x в этой лексической среде.
Обратите внимание, что в отличие от динамических переменных, привязанных к
самому объекту символа, связь между лексическими переменными и символами
присутствует только в интерпретаторе (или компиляторе). Поэтому функции,
принимающие аргумент-символ (например, symbol-value,
boundp и set), могут только извлекать или
изменять динамическое связывание переменной (т.е. содержимое ячейки значения
ее символа).
Также обратите внимание, что переменные могут быть объявлены специальными,
в этом случае они будут использовать динамическое связывание, даже для новых
связываний, таких как связывание let. В зависимости от того,
как объявлена переменная, она может быть специальной глобально, для одного
файла или для части файла. См. Динамическое
связывание для получения подробной информации.