Reading — step 1 of 5
Learn
Common Lisp has TWO kinds of variable bindings:
Lexical (default with let):
(defvar count 10)
(defun inner () count) ;; refers to lexical count if in scope
(let ((count 5))
(inner)) ;; — but lexical doesn't propagate to inner
If count is lexical, inner sees the global, not the inner binding.
Special / dynamic (declared with defvar or defparameter):
(defparameter *count* 10) ;; *earmuffs* by convention for special vars
(defun inner () *count*)
(let ((*count* 5)) ;; rebinds the special variable
(inner)) ;; → 5 — inner sees the dynamic value
The * earmuffs convention marks special variables. Inside a let for a special variable, the binding is on a stack — visible to all callees, restored when the let exits.
declare special to make a single use special:
(let ((x 5))
(declare (special x))
(some-function)) ;; some-function sees this x dynamically
Use cases:
Configuration:
(defparameter *log-level* :info)
(defun log-msg (msg)
(when (member *log-level* '(:debug :info))
(format t "~a~%" msg)))
(let ((*log-level* :error))
(log-msg "this won't print"))
Output redirection:
(defparameter *standard-output* ...)
(let ((*standard-output* (make-string-output-stream)))
(do-something-that-prints)
(get-output-stream-string *standard-output*))
The whole program's print calls now go to the string stream — without changing any code.
Database connection:
(defparameter *db* nil)
(defun execute (sql)
(postmodern:query *db* sql))
(let ((*db* (connect ...)))
(execute "..."))
Each thread / scope can have its own *db* without passing it as an argument.
defvar vs defparameter:
defvar— only sets if undefined (preserves existing value across reloads)defparameter— always sets (reloading the file resets the value)
For true constants, use defconstant (signals an error on redefinition with a different value).
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…