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?
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.