Я поддерживаю хранимые процедуры ( MySQL имеет поддержку хранимых процедур с 5.0 ) с точки зрения безопасности - преимущества -
Недостатки -
То, когда переменная , лексически определил объем , система смотрит туда, где функция , определило для нахождения значения для свободной переменной. Когда переменная , динамично определил объем , система смотрит туда, где функция названа для нахождения значения для свободной переменной. Переменные в языке Common LISP являются все лексическими по умолчанию; однако, динамично ограниченные по объему переменные могут быть определены на верхнем уровне с помощью [1 115] defvar или defparameter.
А более простой пример
лексический обзор (с setq):
(setq x 3)
(defun foo () x)
(let ((x 4)) (foo)) ; returns 3
динамический обзор (с defvar):
(defvar x 3)
(defun foo () x)
(let ((x 4)) (foo)) ; returns 4
, Как делает сообщенный, если переменная является лексической или динамичной? Это не делает. , С другой стороны, когда нечто пойдет для нахождения значения X, это первоначально найдет лексическое значение определенным на верхнем уровне. Это тогда проверяет, чтобы видеть, как ли переменная, предполагается, является динамичной. Если это, то нечто смотрит на среду вызова, которая, в этом случае, использует, позволяют для затемнения значения X, чтобы быть 4.
(примечание: это - упрощение, но оно поможет визуализировать различие между различными правилами обзора)
Возможно, этот пример поможет.
;; the lexical version
(let ((x 10))
(defun lex-foo ()
(format t "Before assignment~18tX: ~d~%" x)
(setf x (+ 1 x))
(format t "After assignment~18tX: ~d~%" x)))
(defun lex-bar ()
(lex-foo)
(let ((x 20)) ;; does not do anything
(lex-foo))
(lex-foo))
;; CL-USER> (lex-bar)
;; Before assignment X: 10
;; After assignment X: 11
;; Before assignment X: 11
;; After assignment X: 12
;; Before assignment X: 12
;; After assignment X: 13
;; the dynamic version
(defvar *x* 10)
(defun dyn-foo ()
(format t "Before assignment~18tX: ~d~%" *x*)
(setf *x* (+ 1 *x*))
(format t "After assignment~18tX: ~d~%" *x*))
(defun dyn-bar()
(dyn-foo)
(let ((*x* 20))
(dyn-foo))
(dyn-foo))
;; CL-USER> (dyn-bar)
;; Before assignment X: 10
;; After assignment X: 11
;; Before assignment X: 20
;; After assignment X: 21
;; Before assignment X: 11
;; After assignment X: 12
;; the special version
(defun special-foo ()
(declare (special *y*))
(format t "Before assignment~18tX: ~d~%" *y*)
(setf *y* (+ 1 *y*))
(format t "After assignment~18tX: ~d~%" *y*))
(defun special-bar ()
(let ((*y* 10))
(declare (special *y*))
(special-foo)
(let ((*y* 20))
(declare (special *y*))
(special-foo))
(special-foo)))
;; CL-USER> (special-bar)
;; Before assignment X: 10
;; After assignment X: 11
;; Before assignment X: 20
;; After assignment X: 21
;; Before assignment X: 11
;; After assignment X: 12
Можно сказать Lisp связывать локальные переменные динамично, также:
(let ((dyn 5))
(declare (special dyn))
... ;; DYN has dynamic scope for the duration of the body
)
Что происходит?
Вы говорите: чувствую, что здесь ничего особенного не происходит. Внешний foo
в bar
увеличивает глобальный x
, а foo
окруженный let
в bar
увеличивает затененный x
на единицу. В чем дело?
Особое , которое здесь происходит, заключается в том, что LET
может затенять значение * x *
. С лексическими переменными это невозможно.
Код объявляет * x *
как специальный через DEFVAR
.
В FOO
теперь значение * x *
ищется динамически. FOO
примет текущую динамическую привязку из * x *
или, если его нет, значение символа для символа * x *
. Новое динамическое связывание может, например, быть введено с помощью LET
.
С другой стороны, лексическая переменная должна где-то присутствовать в лексической среде. LET
, LAMBDA
, DEFUN
и другие могут вводить такие лексические переменные. См. Здесь лексическую переменную x
, введенную тремя разными способами:
(let ((x 3))
(* (sin x) (cos x)))
(lambda (x)
(* (sin x) (cos x)))
(defun baz (x)
(* (sin x) (cos x)))
Если бы наш код был:
(defvar x 0)
(let ((x 3))
(* (sin x) (cos x)))
(lambda (x)
(* (sin x) (cos x)))
(defun baz (x)
(* (sin x) (cos x)))
Тогда X
были специальными во всех трех вышеупомянутых случаях , из-за объявления DEFVAR
, которое объявляет X
как специальный - глобально для всех уровней.По этой причине существует соглашение об объявлении специальных переменных как * X *
. Таким образом, только переменные, окруженные звездами, являются специальными - по соглашению . Это полезное соглашение.
В вашем коде у вас есть следующее:
(defun bar ()
(foo)
(let ((*x* 20))
(foo))
(foo))
Поскольку * x *
объявлен special через DEFVAR
выше в вашем коде, LET
представляет новую динамическую привязку для * x *
. Затем вызывается FOO
. Поскольку внутри FOO
* x *
используется динамическое связывание , он ищет текущий и обнаруживает, что * x *
динамически связан на 20
.
Значение специальной переменной найдено в текущей динамической привязке.
Локальные объявления SPECIAL
Существуют также локальные специальные
объявления:
(defun foo-s ()
(declare (special *x*))
(+ *x* 1))
Если переменная была объявлена специальной с помощью DEFVAR
или ] DEFPARAMETER
, то локальное специальное объявление
можно опустить.
Лексическая переменная напрямую ссылается на привязку переменной:
(defun foo-l (x)
(+ x 1))
Давайте посмотрим на это на практике:
(let ((f (let ((x 10))
(lambda ()
(setq x (+ x 1))))))
(print (funcall f)) ; form 1
(let ((x 20)) ; form 2
(print (funcall f))))
Здесь все переменные лексические. В форме 2 LET
не будет затенять X
в нашей функции f
. Не может. Функция использует лексическую связанную переменную, введенную LET ((X 10)
.Окружение вызова другим лексически связанным X
в форме 2 не влияет на нашу функцию.
Давайте попробуем специальные переменные:
(let ((f (let ((x 10))
(declare (special x))
(lambda ()
(setq x (+ x 1))))))
(print (funcall f)) ; form 1
(let ((x 20)) ; form 2
(declare (special x))
(print (funcall f))))
Что теперь? Это работает?
Не работает!
Первая форма вызывает функцию и пытается найти динамическое значение X
, но его нет. Мы получаем ошибку в форме 1 : X
не связан, потому что не действует динамическое связывание.
Форма 2 будет работать, поскольку LET
со специальным объявлением
вводит динамическую привязку для X
.