EDIT: I changed the example code after the first answer because I came up with a simple version that begs the same questions.
I am currently learning Common Lisp's scoping properties. After I thought I had a solid understanding I decided to code up some examples that I could predict the outcome of, but apparently I was wrong. I have three question, each one relating to an example below:
Example 1:
(defmethod fun1 (x)
(print x)
(fun2))
(defmethod fun2 ()
(print x))
(fun1 5)
Output:
5
*** - EVAL: variable X has no value
Question: This makes sense. x is statically scoped and fun2 has no way of finding the value of x without having it passed explicitly.
Example 2:
(defvar x 100)
(defmethod fun1 (x)
(print x)
(fun2))
(defmethod fun2 ()
(print x))
(fun1 5)
Output:
5
5
Question: I don't understand why x is suddenly visible to fun2 with the value that fun1 gave it, instead of having a value of 100...
Example 3:
(setf x 100)
(defmethod fun1 (x)
(print x)
(fun2))
(defmethod fun2 ()
(print x))
(fun1 5)
Output:
5
100
Question: Should I ignore these results since calling setf on an undeclared variable is apparently undefined? This happens to be what I would expect in my second example...
Any insight would be greatly appreciated...
Answer. Lexical scoping refers to when the location of a function's definition determines which variables you have access to. On the other hand, dynamic scoping uses the location of the function's invocation to determine which variables are available.
Modern Common Lisp doesn't use dynamic scoping any longer.
Lexical scoping, also known as static scoping, is a convention used with many modern programming languages. It refers to setting the scope, or range of functionality, of a variable so that it may be called (referenced) from within the block of code in which it is defined.
R uses lexical scoping, which says the value for z is searched for in the environment where the function was defined. Note: Lexical scoping is also referred to as statical scoping. With dynamic scoping, the variable is bound to the most recent value assigned to that variable.
The effects of setting an undefined variable using setf
is undefined in ANSI Common Lisp.
defvar
will define a special variable. This declaration is global and also has effect on let
bindings. That's the reason that by convention these variables are written as *foo*
. If you have ever defined x
with defvar
, it is declared special and there is no way to declare it lexical later.
let
by default provides local lexical variables. If the variable was already declared special (for example because of a defvar
), then it just creates a new local dynamic binding.
Update
Nothing to see.
x
has been declared special. All uses of the variable x
now use dynamic binding.
When calling the function, you bind x
to 5
. Dynamically. Other functions can now access this dynamic binding and get that value.
This is undefined behavior in Common Lisp. You are setting an undeclared variable. What happens then is implementation dependent. Your implementation (most do something similar) sets the symbol value of x
to 100
. In fun1
, x
is lexically bound. In fun2
evaluating x
retrieves the symbol value (or possibly to the dynamically bound value) of x
.
As an example for an implementation that did (does?) something else: the CMUCL implementation would also have declare x
in example 3 by default to be special. Setting an undefined variable also declares it special.
NOTE
In portable standard compliant Common Lisp code the global variables are defined with defvar
and defparameter
. Both declare these variables to be special. ALL uses of these variables now involve dynamic binding.
Remember:
((lambda (x)
(sin x))
10)
is basically the same as
(let ((x 10))
(sin x))
Which means that variable bindings in let
bindings and variable bindings in function calls are working the same way. If x
would have been declared special in some place earlier, both would involve dynamic binding.
This is specified in the Common Lisp standard. See for example the explanation to the SPECIAL declaration.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With