Функция «set»

#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 …)).