Динамические и Лексические переменные в языке Common LISP

Я поддерживаю хранимые процедуры ( MySQL имеет поддержку хранимых процедур с 5.0 ) с точки зрения безопасности - преимущества -

  1. Большинство баз данных (включая MySQL ) позволяют ограничить доступ пользователей к выполнению хранимых процедур. Четкое управление доступом к безопасности полезно для предотвращения эскалации атак привилегий. Это предотвращает возможность взлома приложений, которые могут быть запущены SQL, непосредственно из базы данных.
  2. Они абстрагируют исходный SQL-запрос из приложения, поэтому для приложения доступно меньше информации о структуре базы данных. Это затрудняет понимание людьми базовой структуры базы данных и разработку подходящих атак.
  3. Они принимают только параметры, поэтому существуют преимущества параметризованных запросов. Конечно, IMO вам все равно нужно дезинфицировать ваш вход, особенно если вы используете динамический SQL внутри хранимой процедуры.

Недостатки -

  1. Они (хранимые процедуры) трудно поддерживать и стремиться к размножению очень быстро. Это делает их проблемой.
  2. Они не очень подходят для динамических запросов - если они созданы для принятия динамического кода в качестве параметров, тогда многие преимущества сбрасываются.

39
задан Josh Lee 5 March 2010 в 03:03
поделиться

4 ответа

То, когда переменная , лексически определил объем , система смотрит туда, где функция , определило для нахождения значения для свободной переменной. Когда переменная , динамично определил объем , система смотрит туда, где функция названа для нахождения значения для свободной переменной. Переменные в языке 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.

(примечание: это - упрощение, но оно поможет визуализировать различие между различными правилами обзора)

26
ответ дан Kyle Cronin 27 November 2019 в 02:16
поделиться

Возможно, этот пример поможет.

;; 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
10
ответ дан Daniel Dickison 27 November 2019 в 02:16
поделиться

Можно сказать Lisp связывать локальные переменные динамично, также:

(let ((dyn 5))
  (declare (special dyn))
  ... ;; DYN has dynamic scope for the duration of the body
  )
7
ответ дан Leslie P. Polzer 27 November 2019 в 02:16
поделиться

Что происходит?

Вы говорите: чувствую, что здесь ничего особенного не происходит. Внешний 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 .

49
ответ дан 27 November 2019 в 02:16
поделиться
Другие вопросы по тегам:

Похожие вопросы: