Variables: Global, Local and Special
6.1 Global Variables and Constants
defvar and defparameter create special (dynamically scoped) variables. Hence the *earmuffs* naming convention.
(defvar *counter* 0) ; defines only if not already defined (keeps the value on reload)
(defparameter *config* "dev") ; always (re)assigns on load
(defconstant +max-size+ 100) ; constant (don't redefine with a different value)
(setf *counter* (1+ *counter*)) ; assignment
(incf *counter*) ; increment (also decf)
(incf *counter* 10)6.2 Local Variables
(let ((x 1)
(y 2)) ; parallel binding
(+ x y)) ; 3
(let* ((x 1)
(y (+ x 1))) ; sequential binding
(* x y)) ; 2
(let ((x 10))
(setf x 20) ; assign a local
x) ; 206.3 setf: Generalized Assignment
setf works on any place (variable, car, aref, gethash, slot accessors, ...), and you can define your own places with defsetf or (defun (setf my-accessor) (new-value obj) ...).
(defparameter *list* (list 1 2 3))
(setf (first *list*) 100) ; *list* → (100 2 3)
(setf (nth 2 *list*) 300)
(defparameter *h* (make-hash-table))
(setf (gethash :a *h*) 1)
(defparameter *v* (make-array 3 :initial-element 0))
(setf (aref *v* 0) 42)
(setf a 1 b 2) ; multiple assignments
(rotatef a b) ; swap
(shiftf a b 99) ; shift values left
(push 0 *list*) (pop *list*) ; stack operations on places
(pushnew 5 *list*) ; push if not already present6.4 Lexical vs Dynamic (Special) Scope
Local let bindings of non-special variables are lexical (closures capture them). Bindings of special variables are dynamic (visible to called functions until the binding exits).
(defvar *level* 0)
(defun show-level () (format t "Level: ~a~%" *level*))
(defun nested ()
(let ((*level* 1)) ; dynamically rebinds the SPECIAL variable
(show-level))) ; Level: 1 (sees the dynamic binding)
(nested)
(show-level) ; Level: 0 (binding restored)
;; Common uses: redirect output, configure behavior temporarily
(let ((*print-base* 16)) (print 255)) ; prints FF
(let ((*standard-output* (make-broadcast-stream))) (print "silenced"))