A local variable is a variable which has a temporary value. For example, when a function is called the variables which are the names of its arguments are temporarily bound to the values of the arguments passed to the function. When the function call exits its arguments are unbound and the previous definitions of the variables come back into view.
A binding is a particular instance of a local variable. Even if a variable has more than one binding currently in place, only the most recent is available—there is no way the previous binding can be accessed until the previous binding is removed.
One way of visualising variable binding is to think of each variable as a stack. When the variable is bound to, a new value is pushed onto the stack, when it is unbound the top of the stack is popped. Similarly when the stack is empty the value of the variable is void (see Void Variables). Assigning a value to the variable (see Setting Variables) overwrites the top value on the stack with a new value. When the value of the variable is required it is simply read from the top of the stack. See also See Fluid Variables.
Apart from function applications there are two special forms which
perform variable binding (i.e. creating local variables),
let creates new variable bindings as specified by the
bindings argument, then evaluates the body-forms in order.
The bindings are then removed, returning all variables to their state
let statement was entered. The value of the statement
is the value of the implicit
The bindings argument is a list of the bindings to perform. Each
binding is either a symbol, in which case that variable is bound to
(), or a list whose car is a symbol. The cdr of this list is a
list of forms which, when evaluated as a
progn, gives the value
to bind to that variable.
(setq foo 42) ⇒ 42 (let ((foo (+ 1 2)) bar) ;; Body forms (setq foo (1+ foo)) ;This sets the new binding (cons foo bar)) ⇒ (4 . ()) foo ⇒ 42 ;The original values is back ;; More on scope. (define a 'outer) (define (foo) a) (define (bar) (let ((a 'inner)) (foo))) (bar) ⇒ outer ;; The let binding is newly established inside of bar, ;; and foo doesn't see it. ;; Difference to defvar. (defvar a 'outer) (bar) ⇒ inner ;; The scope of a is now dynamic.
No bindings are made until all new values have been computed. For example:
(setq foo 42) ⇒ 42 (let ((foo 100) (bar foo)) (cons foo bar)) ⇒ (100 . 42)
foo is given a new binding this is not actually done
until all the new values have been computed, hence
bound to the old value of
The second form,
(let function bindings body...), can be
used to make a loop. (see Looping Structures)
This special form is exactly the same as
let except for one
important difference: the new bindings are installed as they are
You can see the difference by comparing the following example with the
last example in the
let documentation (above),
(setq foo 42) ⇒ 42 (let* ;Using
let*this time ((foo 100) (bar foo)) (cons foo bar)) ⇒ (100 . 100)
By the time the new value of
bar is computed the new binding of
foo is already active.
letrec is similar to
let*, with the
differerence being that the values of bindings are evaluated with all
other bindings in scope. This means that recursive functions may be
letrec. For example, a local factorial function
(letrec ((fact (lambda (n) (if (= n 1) 1 (* n (fact (1- n))))))) (fact 10))
Note also that letrec allows groups of mutually recursive functions to be defined, as in the following example (also from SICP):
(defun f (x) (letrec ((evenp (lambda (n) (if (= n 0) t (oddp (1- n))))) (oddp (lambda (n) (if (= n 0) nil (evenp (1- n)))))) …