I see that the Practical Common Lisp uses (defvar *db* nil)
for setting up a global variable. Isn't it OK to use setq
for the same purpose?
What are the advantages/disadvantages of using defvar
vs. setq
?
assigncommon-lisplispvariable-declarationvariables
I see that the Practical Common Lisp uses (defvar *db* nil)
for setting up a global variable. Isn't it OK to use setq
for the same purpose?
What are the advantages/disadvantages of using defvar
vs. setq
?
To give the short answer, macros are used for defining language syntax extensions to Common Lisp or Domain Specific Languages (DSLs). These languages are embedded right into the existing Lisp code. Now, the DSLs can have syntax similar to Lisp (like Peter Norvig's Prolog Interpreter for Common Lisp) or completely different (e.g. Infix Notation Math for Clojure).
Here is a more concrete example:
Python has list comprehensions built into the language. This gives a simple syntax for a common case. The line
divisibleByTwo = [x for x in range(10) if x % 2 == 0]
yields a list containing all even numbers between 0 and 9. Back in the Python 1.5 days there was no such syntax; you'd use something more like this:
divisibleByTwo = []
for x in range( 10 ):
if x % 2 == 0:
divisibleByTwo.append( x )
These are both functionally equivalent. Let's invoke our suspension of disbelief and pretend Lisp has a very limited loop macro that just does iteration and no easy way to do the equivalent of list comprehensions.
In Lisp you could write the following. I should note this contrived example is picked to be identical to the Python code not a good example of Lisp code.
;; the following two functions just make equivalent of Python's range function
;; you can safely ignore them unless you are running this code
(defun range-helper (x)
(if (= x 0)
(list x)
(cons x (range-helper (- x 1)))))
(defun range (x)
(reverse (range-helper (- x 1))))
;; equivalent to the python example:
;; define a variable
(defvar divisibleByTwo nil)
;; loop from 0 upto and including 9
(loop for x in (range 10)
;; test for divisibility by two
if (= (mod x 2) 0)
;; append to the list
do (setq divisibleByTwo (append divisibleByTwo (list x))))
Before I go further, I should better explain what a macro is. It is a transformation performed on code by code. That is, a piece of code, read by the interpreter (or compiler), which takes in code as an argument, manipulates and the returns the result, which is then run in-place.
Of course that's a lot of typing and programmers are lazy. So we could define DSL for doing list comprehensions. In fact, we're using one macro already (the loop macro).
Lisp defines a couple of special syntax forms. The quote ('
) indicates the next token is a literal. The quasiquote or backtick (`
) indicates the next token is a literal with escapes. Escapes are indicated by the comma operator. The literal '(1 2 3)
is the equivalent of Python's [1, 2, 3]
. You can assign it to another variable or use it in place. You can think of `(1 2 ,x)
as the equivalent of Python's [1, 2, x]
where x
is a variable previously defined. This list notation is part of the magic that goes into macros. The second part is the Lisp reader which intelligently substitutes macros for code but that is best illustrated below:
So we can define a macro called lcomp
(short for list comprehension). Its syntax will be exactly like the python that we used in the example [x for x in range(10) if x % 2 == 0]
- (lcomp x for x in (range 10) if (= (% x 2) 0))
(defmacro lcomp (expression for var in list conditional conditional-test)
;; create a unique variable name for the result
(let ((result (gensym)))
;; the arguments are really code so we can substitute them
;; store nil in the unique variable name generated above
`(let ((,result nil))
;; var is a variable name
;; list is the list literal we are suppose to iterate over
(loop for ,var in ,list
;; conditional is if or unless
;; conditional-test is (= (mod x 2) 0) in our examples
,conditional ,conditional-test
;; and this is the action from the earlier lisp example
;; result = result + [x] in python
do (setq ,result (append ,result (list ,expression))))
;; return the result
,result)))
Now we can execute at the command line:
CL-USER> (lcomp x for x in (range 10) if (= (mod x 2) 0))
(0 2 4 6 8)
Pretty neat, huh? Now it doesn't stop there. You have a mechanism, or a paintbrush, if you like. You can have any syntax you could possibly want. Like Python or C#'s with
syntax. Or .NET's LINQ syntax. In end, this is what attracts people to Lisp - ultimate flexibility.
What's going on?
You say: feel like there is nothing special is going on here. The outer foo
in bar
increments the global x
, and foo
surrounded by let
in bar
increments the shadowed x
. What's the big deal?
The special that's going on here is that LET
can shadow the value of *x*
. With lexical variables that's not possible.
The code declares *x*
to be special via the DEFVAR
.
In FOO
now the value of *x*
is looked up dynamic. FOO
will take the current dynamic binding of *x*
or, if there is none, the symbol value of the symbol *x*
. A new dynamic binding can, for example, be introduced with LET
.
A lexical variable on the other hand has to be present in the lexical environment somewhere. LET
, LAMBDA
, DEFUN
and others can introduce such lexical variables. See here the lexical variable x
introduced in three different ways:
(let ((x 3))
(* (sin x) (cos x)))
(lambda (x)
(* (sin x) (cos x)))
(defun baz (x)
(* (sin x) (cos x)))
If our code were:
(defvar x 0)
(let ((x 3))
(* (sin x) (cos x)))
(lambda (x)
(* (sin x) (cos x)))
(defun baz (x)
(* (sin x) (cos x)))
Then X
were special in all three above cases, because of the DEFVAR
declaration, which declares X
to be special - globally for all levels. Because of this, there is the convention to declare special variables as *X*
. Thus only variables with stars around them are special - by convention. That's a useful convention.
In your code you have then:
(defun bar ()
(foo)
(let ((*x* 20))
(foo))
(foo))
Since *x*
has be declared special via the DEFVAR
above in your code, the LET
construct introduces a new dynamic binding for *x*
. FOO
is then called. Since inside FOO
the *x*
uses dynamic binding, it looks up the current one and finds that *x*
is dynamically bound to 20
.
The value of a special variable is found in the current dynamic binding.
Local SPECIAL declarations
There are also local special
declarations:
(defun foo-s ()
(declare (special *x*))
(+ *x* 1))
If the variable had been declared special by a DEFVAR
or DEFPARAMETER
, then the local special
declaration can be omitted.
A lexical variable directly references the variable binding:
(defun foo-l (x)
(+ x 1))
Let's see it in practice:
(let ((f (let ((x 10))
(lambda ()
(setq x (+ x 1))))))
(print (funcall f)) ; form 1
(let ((x 20)) ; form 2
(print (funcall f))))
Here all variables are lexical. In form 2 the LET
will not shadow the X
in our function f
. It can't. The function uses the lexical bound variable, introduced by the LET ((X 10)
. Surrounding the call with another lexically bound X
in form 2 has no effect on our function.
Let's try special variables:
(let ((f (let ((x 10))
(declare (special x))
(lambda ()
(setq x (+ x 1))))))
(print (funcall f)) ; form 1
(let ((x 20)) ; form 2
(declare (special x))
(print (funcall f))))
What now? Does that work?
It does not!
The first form calls the function and it tries to look up the dynamic value of X
and there is none. We get an error in form 1: X
is unbound, because there is no dynamic binding in effect.
Form 2 would work, since the LET
with the special
declaration introduces a dynamic binding for X
.
Best Answer
There are several ways to introduce variables.
DEFVAR and DEFPARAMETER introduce global dynamic variables.
DEFVAR
optionally sets it to some value, unless it is already defined.DEFPARAMETER
sets it always to the provided value. SETQ does not introduce a variable.Notice that you likely never want to
DEFVAR
variables with names likex
,y
,stream
,limit
, ... Why? Because these variables then would be declared special and its difficult to undo that. The special declaration is global and all further uses of the variable would use dynamic binding.BAD:
BETTER: Always mark special variables with
*
in their names!Local variables are introduced with DEFUN, LAMBDA, LET, MULTIPLE-VALUE-BIND and many others.
Now, by default the local variables in above two forms are lexical, unless they are declared SPECIAL. Then they would be dynamic variables.
Next, there are also several forms to set a variable to new values. SET, SETQ, SETF and others.
SETQ
andSETF
can set both lexical and special (dynamic) variables.It is required for portable code that one sets variables that are already declared. The exact effect of setting a not declared variable is undefined by the standard.
So, if you know what your Common Lisp implementation does, you can use
in the Read-Eval-Print-Loop at the toplevel. But don't use it in your code, since the effect is not portable. Typically
SETQ
will set the variable. But some implementation might also declare the variable SPECIAL when it doesn't know it (CMU Common Lisp does that by default). That's almost always not what one would want. Use it for casual use if you know what you do, but not for code.Same here:
First, such variables should be written as
*world*
(with the surrounding*
characters), to make clear that it is a global special variable. Second, it should have been declared withDEFVAR
orDEFPARAMETER
before.A typical Lisp compiler will complain that above variable is undeclared. Since global lexical variables don't exist in Common Lisp, the compiler has to generate code for a dynamic lookup. Some compiler then say, okay, we assume that this is a dynamic lookup, let's declare it to be special - since that is what we assume anyway.