Я читаю книгу "Практический общий Lisp" Питера Сейбеля.
В главе 6 разделы "Переменные" "Лексические переменные и замыкания" и "Динамические, a.k.a. Special, Variables". http://www.gigamonkeys.com/book/variables.html
Моя проблема в том, что примеры в обоих разделах показывают, как (пусть...) может теневать глобальные переменные и на самом деле не говорит о различии между динамическими и лексическими варами.
Я понимаю, как работают замыкания, но на самом деле я не понимаю, что в этом примере есть что-то особенное:
(defvar *x* 10)
(defun foo ()
(format t "Before assignment~18tX: ~d~%" *x*)
(setf *x* (+ 1 *x*))
(format t "After assignment~18tX: ~d~%" *x*))
(defun bar ()
(foo)
(let ((*x* 20)) (foo))
(foo))
CL-USER> (foo)
Before assignment X: 10
After assignment X: 11
NIL
CL-USER> (bar)
Before assignment X: 11
After assignment X: 12
Before assignment X: 20
After assignment X: 21
Before assignment X: 12
After assignment X: 13
NIL
Я чувствую, что здесь ничего особенного не происходит. Внешний foo в баре увеличивает глобальный x, а foo, окруженный буквой let, увеличивает затененный x. Какая большая сделка? Я не понимаю, как это должно объяснить разницу между лексическими и динамическими варами. Однако книга продолжается следующим образом:
Итак, как это работает? Как LET знайте, что когда он связывает x, это предполагается создать динамическую привязку а не нормальное лексическое связывание? Он знает, потому что имя было объявлено специальным .12 Название каждого переменная, определенная с помощью DEFVAR и DEFPARAMETER автоматически объявляется глобально специальные.
Что произойдет, если бы связать x с помощью "нормального лексического привязки" ? В целом, каковы различия между динамической и лексической привязкой и как этот пример особенный относительно динамической привязки?