2

test.lisp:

(defvar test
  #'(lambda (var1)
      #'(lambda (var2)
          `((var1 . ,var1)
            (var2 . ,var2)))))
(defvar var1 'wrong)
(defvar var2 'wrong)

And in the REPL:

$ clisp -q -i test.lisp
;; Loading file test.lisp ...
;; Loaded file test.lisp
[1]> (funcall (funcall test 'right) 'right)
((VAR1 . WRONG) (VAR2 . RIGHT))

I thought that common lisp was supposed to be lexically scoped these days, so why is the value of var1 not captured by the inner lambda in test? How can I make sure it is captured?

Matt
  • 21,026
  • 18
  • 63
  • 115

2 Answers2

4

This is visible when using an interpreter.

Let's look at a compiler first:

? (load "/tmp/test.lisp")
#P"/private/tmp/test.lisp"
? (funcall (funcall test 'right) 'right)
((VAR1 . RIGHT) (VAR2 . RIGHT))

First the functions are getting compiled. The compiler assumes lexical binding. Then DEFVAR declares the variables VAR1 and VAR2 to be special (-> not lexical). In the executed code then, the code is still using lexical binding.

You were using an Interpreter:

First the functions are loaded. Nothing gets compiled. Then DEFVAR declares VAR1 and VAR2 as special.

In the executed code then, the Interpreter is using dynamic binding - like you declared it. The Interpreter looks at the variables at runtime and sees that they are declared to be special.

Difference:

The compiler has generated the machine code before the special declaration. Thus at runtime it uses lexical binding.

The interpreter looks at runtime at the existing declarations.

Style

If you want to avoid dynamic binding, don't declare variables to be special.

Rainer Joswig
  • 136,269
  • 10
  • 221
  • 346
  • As I asked in a comment below, how can I define `var1` and `var2` globally without declaring them special? – Matt Apr 10 '15 at 21:27
  • 1
    @Matt: basically you can't. Just use different names. Style is to write special variables as `*var1*`. – Rainer Joswig Apr 10 '15 at 21:29
  • What about not basically? I have some variables that are better off being single letters, but they end up interfering with everything. I would be much happier having them be lexically scoped than having them be difficult to type. – Matt Apr 10 '15 at 21:36
  • 1
    @Matt: you don't want to go that route. Just use different names. That's kind of ugly, but accepted style. – Rainer Joswig Apr 10 '15 at 21:38
  • Maybe I won't want to go that route, but I won't know that unless I know what it entails. I don't care about the ugliness (I actually like the way `*special-variables*` look), I only care about these particular few variables being very fast to type. – Matt Apr 10 '15 at 21:41
  • @matt Common Lisp does not provide a portable way of accessing a global lexical state. The only globally bound variables are special and have dynamic extent. – Vatine Apr 12 '15 at 15:12
  • @Vatine: Thanks. Do you know if there is a reason for that (other than historically)? – Matt Apr 13 '15 at 13:47
  • @matt No, I don't know. One of the things I could speculate about is that you really want your lexical context to be fully available at time of analyzing it and if you have a lexical "top-level" scope, you don't have that guarantee, so I guess there are interesting problems to solve there. – Vatine Apr 13 '15 at 14:33
  • @Vatine: Isn't it the other way around? If the top-level scope is lexical, then lexical context does not depend on the top level except for free variables. If the top-level scope is dynamic, then you can't analyze any lexical scope because you don't know which variables might be defined dynamically at the top level, giving compiler-interpreter discrepancies such as the one in the answer above. – Matt Apr 13 '15 at 19:05
  • @matt Any "not bound" variable will trigger a warning when compiling a function, for that reason. Since we don't know if the variable is dynamic or lexical in scope, we can't compile it. You can declare variables (inside the function) as being of dynamic extent, at which point they will be considered dynamic, rather than lexical. Basically, "don't reference free variables, unless they're dynamic" is the strongly worded advice of the land. – Vatine Apr 14 '15 at 08:51
  • @Vatine: If the free variable is bound in any surrounding lexical scope, the compiler should be able to know about it, since lexical scopes are known at compile time. Of course if the variable is not bound at all, there would be an error or warning or whatever. So your "strongly worded advice" only applies because that's how Common Lisp happens to work, and not because it makes sense in general. – Matt Apr 14 '15 at 18:03
3

defvar (and defparameter) declare the variable to be special (dynamic). Give your special variables *earmuffs* to prevent surprises about whether a binding is lexical or dynamic.

m-n
  • 1,476
  • 1
  • 9
  • 9
  • So how can I define `var1` and `var2` globally without making them dynamically scoped? – Matt Apr 10 '15 at 21:21
  • 1
    The desired behavior can be produced using symbol macros. Implementations of it are sometimes called `deflex`, e.g. http://rpw3.org/hacks/lisp/deflex.lisp I agree with Rainer about avoiding them, with the exception of variables used for capturing results while playing at the repl, which I find much nicer as lexical vars without the `**`. – m-n Apr 10 '15 at 23:08