Ссылки на переменную в шепелявости

Можно пользоваться одной из популярных библиотек Ajax, которые делают это для Вас исходно. Мне нравится Прототип . Можно просто добавить evalScripts:true как часть вызова Ajax, и это происходит автоволшебно.

26
задан Tamas Czinege 11 August 2009 в 19:55
поделиться

5 ответов

С лексической областью видимости у человека нет доступа к переменным, которые не являются в текущей области. Вы также не можете напрямую передавать лексические переменные в другие функции. 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
24
ответ дан 28 November 2019 в 07:29
поделиться

Хотя Common Lisp поддерживает стиль функционального программирования, это не является его основным направлением (Scheme, хотя и не является чисто функциональным, но гораздо ближе). Common Lisp очень хорошо поддерживает полностью императивный стиль программирования.

Если вы обнаружите, что вам нужно написать такой код, обычным решением будет макрос:

(defmacro increase-by-one (var)
  `(setf ,var (+ ,var 1)))

Это позволяет вам написать такой код:

(increase-by-one foo)

который будет расширен до:

(setf foo (+ foo 1))

перед компиляцией.

9
ответ дан 28 November 2019 в 07:29
поделиться

Конечно, в Лиспе вы можете сделать свой собственный способ создания ссылок на переменные, если хотите. Самый простой подход выглядит так:

(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
8
ответ дан 28 November 2019 в 07:29
поделиться

Я думаю, вы упускаете один из ключевые концепции функционального программирования - вы не должны изменять состояние объектов после их создания.

0
ответ дан 28 November 2019 в 07:29
поделиться

Макросы возможно, то, что вы хотите, потому что они не оценивают свои аргументы, поэтому, если вы передадите имя переменной, вы получите имя переменной, а не ее значение.

INCF сделает именно то, что вы хотите, поэтому, если вы погуглите "defmacro incf" вы найдете множество определений для этого, некоторые из которых даже близки к правильным. : -)

Редактировать: Я предлагал INCF не как альтернативу написанию собственного, а потому, что он делает то, что вы хотите, и является макросом, поэтому вы можете легко найти его исходный код, например, ABCL или CMUCL .

1
ответ дан 28 November 2019 в 07:29
поделиться