Local dynamic binding in general lisp
Indeed, I'm not sure I fully understand what it means for a binding to be "dynamic" and "lexical". But I understand that when I use defvar
or defparameter
to define a binding, 1. it declares a global variable 2. the binding is declared "special" so that it can be shadowed by a new local binding, for example
(defvar *x* 3)
(defun f () *x*)
(f) ;=>3
(let ((*x* 2)) (f));=>2
Now, my question is, is it possible to have a local binding (i.e. a binding that doesn't pollute the global environment) that has the same property (i.e. can be shadowed by "outer" / "new" bindings)?
Example:
(special-binding ((x 1)) (defun f () x))
(f);=>1
x;=>error, no binding in the global environment
(let ((x 2)) (f));=>2
I tried using declarations (special x)
in a block let
or (locally (declare (special x)) ...)
, but it doesn't seem to create a closure (asking for the value of a variable from a function defined this way triggers "Unbound-Variable" ").
source to share
First, a dynamic variable only takes a value from dynamic bindings, not lexical ones:
(defun f ()
(declare (special x))
x)
(let ((x 1))
;; without this declaration, we would get an unbound variable error
(declare (special x))
(f))
;; => 1
You can get the default for local dynamic binding with progv
:
(defun b ()
(progv (if (boundp 'x) () '(x))
(if (boundp 'x) () '(1))
(locally (declare (special x))
x)))
(let ((x 2))
(declare (special x))
(b))
;; -> 2
(b)
;; -> 1
source to share
You cannot grab dynamic bindings in a closure, only lexical bindings.
You need to declare the variable special in the function, so it will use dynamic binding:
(defun f ()
(declare (special x))
x)
Then you need to bind the variable dynamically around the call using:
(let ((x 1))
(declare (special x))
(f))
source to share