10

I want to rebind a special variable inside of a loop. Now, normally, this is accomplished using a let.

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

But since the loop macro has these nice with clauses, I thought I might be able to do so in there. The expression (macroexpand '(loop with *read-eval* = nil)) ends up expanding the binding to a let, so it will definitely work on my implementation specifically. But I can't find anything in the standard indicating that this is standardized behavior. So, I suppose, my question is this:

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

Are conforming implementations required to modify the existing *read-eval* variable, or is there a risk that they might create a new lexical variable of the same name?

sds
  • 58,617
  • 29
  • 161
  • 278
Silvio Mayolo
  • 62,821
  • 6
  • 74
  • 116

1 Answers1

8

*read-eval* is a global special variable. There is no way to undo that, i.e., create a local lexical binding for it.

with clause is described as using bindings (as opposed to mere setting) which means that, indeed, once the loop is done, we'll be back to the original value (to answer @joshua-tailor's question).

Let us think rationally. (loop with foo = nil ...) definitely does establish a binding for foo. So, for (loop with *read-eval* = nil ...) not to establish that binding, the implementation has to check (at macroexpansion or compile time) whether *read-eval* will be a dynamic variable at run time. This sounds insane.

sds
  • 58,617
  • 29
  • 161
  • 278
  • 2
    This is true, but it's still not clear that **loop** has to rebind, as opposed to just assigning. Do we know that once the loop is done, we'll be back to the original value? I'm pretty sure the answer is yes, based on http://www.lispworks.com/documentation/HyperSpec/Body/06_abb.htm, which says that the variables cease to exist outside the loop. The phrasing doesn't work particularly well for special variables, but it looks like the only reasonable interpretations are a local binding of the name, which would mean *let* (or *lambda*, etc.). – Joshua Taylor Oct 30 '15 at 02:51