Next: , Up: Variables   [Contents][Index]


5.8.1 Local Variables

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 and let*.

Macro: let bindings body-forms…

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 before the let statement was entered. The value of the statement is the value of the implicit progn.

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)

Although foo is given a new binding this is not actually done until all the new values have been computed, hence bar is bound to the old value of foo.

The second form, (let function bindings body...), can be used to make a loop. (see Looping Structures)

Macro: let* bindings body-forms…

This special form is exactly the same as let except for one important difference: the new bindings are installed as they are computed.

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.

Macro: letrec bindings body-forms…

letrec is similar to let and 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 defined with letrec. For example, a local factorial function (from SICP):

(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))))))
    …

Next: , Up: Variables   [Contents][Index]