Общий лиспингский обзор (динамический и лексический) - PullRequest
9 голосов
/ 17 октября 2011

РЕДАКТИРОВАТЬ: я изменил пример кода после первого ответа, потому что я пришел к простой версии, которая задает те же вопросы.

В настоящее время я изучаю свойства области видимости Common Lisp.После того, как я подумал, что у меня есть твердое понимание, я решил кодировать некоторые примеры, по которым я мог предсказать результат, но, очевидно, я ошибался.У меня есть три вопроса, каждый из которых относится к примеру ниже:

Пример 1:

(defmethod fun1 (x)
  (print x)
  (fun2))

(defmethod fun2 ()
  (print x))

(fun1 5)

Вывод:

5 
*** - EVAL: variable X has no value

Вопрос: Это имеет смысл.x имеет статическую область видимости, и fun2 не может найти значение x, не передав его явно.

Пример 2:

(defvar x 100)

(defmethod fun1 (x)
  (print x)
  (fun2))

(defmethod fun2 ()
  (print x))

(fun1 5)

Вывод:

5
5

Вопрос: Я не понимаю, почему x внезапно становится видимым для fun2 со значением, которое ему дало fun1, вместо значения 100 ...

Пример 3:

(setf x 100)

(defmethod fun1 (x)
  (print x)
  (fun2))

(defmethod fun2 ()
  (print x))

(fun1 5)

Вывод:

5
100

Вопрос: Должен ли я игнорировать эти результаты, так как вызов setf для необъявленной переменной, по-видимому, не определен?Это то, что я ожидаю во втором примере ...

Любое понимание будет с благодарностью ...

1 Ответ

18 голосов
/ 17 октября 2011

Эффект установки неопределенной переменной с помощью SETF не определен в ANSI Common Lisp.

DEFVAR определит специальную переменную.Это объявление является глобальным и также влияет на привязки LET.По этой причине условно эти переменные записываются как *foo*.Если вы когда-либо определяли X с помощью DEFVAR, он объявляется специальным, и позже нет способа объявить его лексическим.

LET по умолчанию предоставляет локальные лексические переменные.Если переменная уже была объявлена ​​специальной (например, из-за DEFVAR), она просто создает новое локальное динамическое связывание.

Обновление

  • Пример 1,

Ничего не видно.

  • Пример 2

X объявлен специальным.Все применения переменной X теперь используют динамическое связывание.При вызове функции вы привязываете X к 5. Динамически.Другие функции теперь могут получить доступ к этой динамической привязке и получить это значение.

  • Пример 3

Это неопределенное поведение в Common Lisp.Вы устанавливаете необъявленную переменную.То, что происходит тогда, зависит от реализации.Ваша реализация (большинство делают что-то подобное) устанавливает значение символа X равным 100. В FUN1 X лексически связан.В FUN2 вычисление X возвращает значение символа (или, возможно, динамически связанное значение) X.

В качестве примера для реализации, которая сделала (делает?) Что-то еще: реализация CMUCL также должна была бы объявить X вПример 3 по умолчанию будет особенным.Установка неопределенной переменной также объявляет ее специальной.

NOTE

В переносимом стандартном Common Lisp-коде глобальные переменные определяются с помощью DEFVAR и DEFPARAMETER.Оба объявляют эти переменные как особые.ВСЕ использование этих переменных теперь включает динамическое связывание.

Помните:

((lambda (x)
   (sin x))
 10)

в основном совпадает с

(let ((x 10))
  (sin x))

Это означает, что привязки переменных в привязках LET ипривязки переменных в вызовах функций работают одинаково.Если бы X ранее был объявлен специальным в каком-то месте, оба варианта включали бы динамическое связывание.

Это указано в стандарте Common Lisp.См., Например, пояснение к СПЕЦИАЛЬНОЙ декларации .

...