#dynamic #lisp #common-lisp #scoping #lexical
#динамический #lisp #common-lisp #определение области действия #лексический
Вопрос:
РЕДАКТИРОВАТЬ: я изменил пример кода после первого ответа, потому что я придумал простую версию, которая задает те же вопросы.
В настоящее время я изучаю свойства области видимости 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. Вот мое наивное объяснение после небольшой игры… дайте мне знать, если я близок.. Пример 1: не требует пояснений Пример 2: объявление x как динамической переменной приводит к поиску всех экземпляров x во время выполнения в стеке динамических переменных, что приведет к тому, что fun2 унаследует значение x от fun1, несмотря на то, что он не является динамической переменной. Пример3: понятия не имею… Я думаю, что это не определено
2. Задавать вопросы — это хорошо. Задавать вопросы — это плохо.
3. Вместо DEFMETHOD используйте DEFUN . В этих примерах метод ОПРЕДЕЛЕНИЯ не требуется. DEFUN создает простую функцию. DEFMETHOD предназначен для общих функций, где требуется некоторая диспетчеризация.
Ответ №1:
Последствия установки неопределенной переменной с использованием setf
не определены в ANSI Common Lisp.
defvar
определит специальную переменную. Это объявление является глобальным и также влияет на let
привязки. Это причина, по которой по соглашению эти переменные записываются как *foo*
. Если вы когда-либо определяли x
с defvar
помощью, он объявлен специальным, и нет никакого способа объявить его лексическим позже.
let
по умолчанию предоставляет локальные лексические переменные. Если переменная уже была объявлена специальной (например, из-за a defvar
), то она просто создает новую локальную динамическую привязку.
Обновить
- Пример 1 .
Ничего не видно.
- Пример 2
x
был объявлен специальным. Все виды использования переменной x
теперь используют динамическую привязку. При вызове функции вы привязываетесь x
к 5
. Динамически. Теперь другие функции могут получить доступ к этой динамической привязке и получить это значение.
- Пример 3
Это неопределенное поведение в Common Lisp. Вы устанавливаете необъявленную переменную. То, что происходит тогда, зависит от реализации. Ваша реализация (большинство делает что-то подобное) устанавливает значение символа x
to 100
. В fun1
, x
является лексически связанным. При fun2
оценке x
извлекается значение символа (или, возможно, динамически привязанное значение) x
.
В качестве примера для реализации, которая сделала (делает?) что-то еще: реализация CMUCL также должна была бы объявлять x
в примере 3 по умолчанию особенной. Установка неопределенной переменной также объявляет ее специальной.
ПРИМЕЧАНИЕ
В коде Common Lisp, совместимом с переносимым стандартом, глобальные переменные определяются с defvar
помощью и defparameter
. Оба объявляют эти переменные особыми. ВСЕ виды использования этих переменных теперь включают динамическую привязку.
Помните:
((lambda (x)
(sin x))
10)
в основном такой же, как
(let ((x 10))
(sin x))
Это означает, что привязки переменных в let
привязках и привязки переменных в вызовах функций работают одинаково. Если x
бы это было объявлено специальным в каком-то месте ранее, оба они включали бы динамическое связывание.
Это указано в стандарте Common Lisp. См., Например, Объяснение СПЕЦИАЛЬНОГО объявления.
Комментарии:
1. Я обновил свой первоначальный пост более точными примерами и вопросами, которые отражают то, что мне было трудно понять. В частности, поведение, продемонстрированное в моем втором примере, по сравнению с моим первым примером
2. Спасибо за разъяснение! Я не думаю, что я ожидал, что значения параметров функций будут выполняться так же, как обычные свободные переменные… но я полагаю, что каждое упоминание обрабатывается одинаково.
3. @antman8969: использование переменных везде одинаково. Что немного удивительно, так это то, что параметры функции также могут быть динамически привязаны и что на них влияет определение переменных с помощью DEFVAR .