2015-10-30 3 views
10

Я хочу перестроить специальную переменную внутри цикла. Теперь, как правило, это достигается с помощью let.Common Lisp Binding in Loop Macro

(let ((*read-eval* nil)) 
    (do-something-here)) 

Но поскольку loop макрокоманда имеет эти хорошие with положения, я думал, что я мог бы быть в состоянии сделать это там. Выражение (macroexpand '(loop with *read-eval* = nil)) приводит к расширению привязки к let, поэтому он определенно будет работать над моей реализацией. Но я ничего не могу найти в the standard, что указывает на стандартизованное поведение. Таким образом, я полагаю, мой вопрос заключается в следующем:

(loop with *read-eval* = nil 
     for i from 1 to 10 
     do (something-involving-the-read-function)) 

ли корректные реализации, необходимых для изменения существующей *read-eval* переменного, или существует риск того, что они могли бы создать новую лексическую переменные с тем же именем?

ответ

7

*read-eval* - глобальная специальная переменная. Невозможно отменить это, т. Е. Создать для него локальную лексическую привязку.

with положения описывается, как с помощью bindings (в отличие от простого заходящего), что означает, что, действительно, когда цикл закончен, мы вернемся к исходному значению (ответить @ Joshua-портной вопрос).

Давайте рассуждать рационально. (loop with foo = nil ...) определенно устанавливает привязку для foo. Итак, для (loop with *read-eval* = nil ...)не, чтобы установить это обязательство, реализация должна проверить (при макрорасширении или времени компиляции), будет ли *read-eval* во время выполнения dynamic variable. Это звучит безумно.

+2

Это правда, но до сих пор неясно, что ** loop ** необходимо переустановить, а не просто назначать. Знаем ли мы, что как только цикл будет завершен, мы вернемся к исходному значению? Я уверен, что ответ да, на основе http://www.lispworks.com/documentation/HyperSpec/Body/06_abb.htm, в котором говорится, что переменные перестают существовать вне цикла. Фраза не работает особенно хорошо для специальных переменных, но похоже, что единственными разумными интерпретациями являются локальное связывание имени, что будет означать * let * (или * lambda * и т. Д.). –