С лексической областью у человека нет доступа к переменным, которые не находятся в текущей области. Вы также не можете передавать лексические переменные другим функциям напрямую. Lisp оценивает переменные и передает значения, связанные с этими переменными. Нет ничего лучше, чем первоклассные ссылки на переменные.
Думай функционально!
(let ((a 1))
(values (lambda (new-value)
(setf a new-value))
(lambda () a)))
выше возвращает две функции. Один может читать переменную, другой может писать переменную.
Давайте назовем первую функцию writer
, а вторую reader
.
(defun increase-by-one (writer reader)
(funcall writer (1+ (funcall reader))))
Итак, чтобы делать то, что вы хотите, код должен: а) находиться в области видимости или б) иметь доступ к функциям, входящим в область действия.
Также переменная может быть глобальной .
(defvar *counter* 1)
(defun increase-by-one (symbol)
(set symbol (1+ (symbol-value symbol))))
; note the use of SET to set a symbol value
(increase-by-one '*counter*)
Это работает для глобальных переменных, которые представлены символом. Это не работает для лексических переменных - они не представлены символом.
Существует также макрос INCF
, который увеличивает «место» (например, переменную).
(incf a)
Но a
- это переменная в текущей области видимости.
(defun foo (a)
(incf a)) ; increases the local variable a
Здесь видно ограничение :
(defun foo (var)
(add-one-some-how var))
(let ((a 1))
(foo something-referencing-a))
Невозможно передать прямую ссылку от a
до FOO
.
Единственный способ - предоставить функцию. Мы также должны переписать FOO
, чтобы он вызывал предоставленную функцию.
(defun foo (f)
(funcall f 1)) ; calls the function with 1
(let ((a 1))
(foo (lambda (n)
(setf a (+ a n)))))
;; passes a function to foo that can set a