Можно пользоваться одной из популярных библиотек Ajax, которые делают это для Вас исходно. Мне нравится Прототип . Можно просто добавить evalScripts:true как часть вызова Ajax, и это происходит автоволшебно.
С лексической областью видимости у человека нет доступа к переменным, которые не являются в текущей области. Вы также не можете напрямую передавать лексические переменные в другие функции. Lisp оценивает переменные и передает значения, связанные с этими переменными. Нет ничего лучше первоклассных ссылок на переменные.
Думайте функционально!
(let ((a 1))
(values (lambda (new-value)
(setf a new-value))
(lambda () a)))
выше возвращает две функции. Одна может читать переменную, другая может записывать переменную.
Let ' s вызывают первую функцию 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
Хотя Common Lisp поддерживает стиль функционального программирования, это не является его основным направлением (Scheme, хотя и не является чисто функциональным, но гораздо ближе). Common Lisp очень хорошо поддерживает полностью императивный стиль программирования.
Если вы обнаружите, что вам нужно написать такой код, обычным решением будет макрос:
(defmacro increase-by-one (var)
`(setf ,var (+ ,var 1)))
Это позволяет вам написать такой код:
(increase-by-one foo)
который будет расширен до:
(setf foo (+ foo 1))
перед компиляцией.
Конечно, в Лиспе вы можете сделать свой собственный способ создания ссылок на переменные, если хотите. Самый простой подход выглядит так:
(defstruct reference getter setter)
(defmacro ref (place)
(let ((new-value (gensym)))
`(make-reference :getter (lambda () ,place)
:setter (lambda (,new-value)
(setf ,place ,new-value)))))
(defun dereference (reference)
(funcall (reference-getter reference)))
(defun (setf dereference) (new-value reference)
(funcall (reference-setter reference) new-value))
А затем вы можете использовать его:
(defun increase-by-one (var-ref)
(incf (dereference var-ref)))
(defun test-inc-by-one (n)
(let ((m n))
(increase-by-one (ref m))
(values m n)))
(test-inc-by-one 10) => 11, 10
Я думаю, вы упускаете один из ключевые концепции функционального программирования - вы не должны изменять состояние объектов после их создания.
Макросы возможно, то, что вы хотите, потому что они не оценивают свои аргументы, поэтому, если вы передадите имя переменной, вы получите имя переменной, а не ее значение.
INCF сделает именно то, что вы хотите, поэтому, если вы погуглите "defmacro incf" вы найдете множество определений для этого, некоторые из которых даже близки к правильным. : -)
Редактировать: Я предлагал INCF не как альтернативу написанию собственного, а потому, что он делает то, что вы хотите, и является макросом, поэтому вы можете легко найти его исходный код, например, ABCL или CMUCL .