Общая область видимости Lisp (динамическая и лексическая)

EDIT: я изменил код примера после первого ответа, потому что я придумал простую версию, которая вызывает те же вопросы.

в настоящее время я изучаю свойства области видимости 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 ответов


эффекты установки неопределенной переменной с помощью 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 по умолчанию специальным. Установка неопределенной переменной также объявляет ее специальной.

Примечание

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

помните:

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

в основном то же самое, что

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

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

это указано в стандарте Common Lisp. См., например, объяснение специальная декларация.