#common-lisp #dynamic-binding #lexical-scope
#common-lisp #динамическая привязка #лексическая область
Вопрос:
У меня возникают трудности с пониманием работы части кода, которую может понять кто-то с большим опытом:
(let ((x 0))
(loop for var in '(x)
do (set var 3))
x)
Я ожидаю, что выражение должно вернуть 3, новое значение x, но на самом деле оно возвращает 0. Почему x не сбрасывается? Есть ли другой способ перебирать список переменных и присваивать им значения?
Комментарии:
1.
X
является лексической переменной.SET
задает только интервал значений символа (другими словами, он задает значение глобальной переменной).2. @jkiiski: это ответ, а не комментарий.
3.
set
устарела, поэтому вам не следует ее использовать. Используйтеsetf
специальную форму для изменения привязок, специальных глобальных или лексических. Обновление привязок на основе символа, который выглядит одинаково, вероятно, необходимо решать с помощью других структур данных, таких как хэш-таблицы.
Ответ №1:
Доступ к лексическим переменным с использованием символов не поддерживается.
Common Lisp не предоставляет вам доступ к лексическим переменным через символы. По умолчанию переменные связаны лексически.
Специальные переменные используют динамическую привязку.
Она работает со специальными переменными, которые используют динамическую привязку:
CL-USER 14 > (let ((x 0))
(declare (special x))
(loop for var in '(x) do (set var 3))
x)
3
В качестве альтернативы вы можете объявить глобальную специальную переменную, и специальное объявление распространяется на let
привязки. Именно поэтому их визуально помечают соглашением об именовании. Мы пишем *foo*
и не foo
.
CL-USER 15 > (defvar *x123* 0)
*X123*
CL-USER 16 > (let ((*x123* 1))
(loop for var in '(*x123*) do (set var 3))
*x123*)
3
Комментарии:
1. Не могли бы вы немного подробнее рассказать о том, что означает отсутствие доступа к лексическим переменным через символы? Например, имеет ли лексический var обычные слоты символов, такие как print-name, symbol-value, symbol-function, prop list и т.д.? Или у lex var никогда не бывает символа в качестве его символьного значения? Спасибо за любые разъяснения и извините, если это элементарно. (продолжение ниже)
2. Во-вторых, я надеялся избежать использования глобальных переменных. Пользователь будет указывать имена переменных (полученные с помощью макросов). В настоящее время я создаю предложение let (во время загрузки) с этими именами переменных (см. Выше мой пример с одной переменной с именем x), а затем соответствующим образом устанавливаю их значения в теле. Если «set» недоступен для переменных lex, то остается ли «setq» (или «setf») единственным оставшимся способом? Но тогда, похоже, я не могу сгруппировать все эти имена переменных в список и обработать каждое из них с помощью переменной цикла. Есть ли какой-либо другой способ установить значения (все числа) в let? (продолжение ниже)
3. Возможно, единственная другая идея, которая у меня была, — это создать отдельный пользовательский пакет (или, возможно, использовать пакет :keywords) и поместить туда эти имена. Но это может потребовать некоторого существенного переписывания / переосмысления кода. Ищу какие-либо опытные идеи. Спасибо.
4. Хорошо, спасибо, Райнер. При дальнейшем чтении я смог исправить некоторые ошибочные представления о лексических и специальных переменных. Просто игнорируйте мои предыдущие комментарии. Я могу использовать упомянутое вами решение (declare (special …)).