# Local declarations

There are two widely-used forms of local declaration in Lisp:
`let`

and `let*`

.

## let

The purpose of local declarations is, just as in any other language, to name
intermediate results. The scope of identifiers created by a `let`

is lexical, that is the `let`

expression, but their extent is
indefinite (see anonymous functions).
`let`

looks like this:
(let ((id-1 exp-1)
...
(id-m exp-m))
exp-m+1
...
exp-n)
Each of the expressions `exp-i`

, i<=m, is evaluated and the
resulting values are associated with the corresponding `id-i`

.
Subsequently, the expressions `exp-i`

, m<i<=n are
evaluated *in order*. The result of the `let`

expression is the result of `exp-n`

.
user> (let ((x (+ 1 2)) (y ticks-per-second))
(+ (* x x x) (* y y)))
1000027.00000000
Note that the input expression extends over more than one line. Lisp will keep
waiting for input as long as the number of close parentheses is less than the
number of open parentheses. In this example, `x`

is initialized
with the value `3`

and `y`

with the value
`1000.00000000000`

. The result is the sum of
`x`

cubed and `y`

squared.
## let*

Syntactically, `let*`

is the same as `let`

, as
shown above, with the substitution of `let*`

for
`let`

. The semantic difference with `let*`

is
that each expression `exp-i`

can refer to the results of earlier
initialization expressions. Whereas with `let`

, the
`exp-i`

were evaluated first and then associated with the
corresponding `id-i`

, with `let*`

, each
`exp-i`

is evaluated and the result associated with the
corresponding `id-i`

*before* starting on the
evaluation of the `exp-i+1`

. In effect, `let*`

is
*equivalent* to:
(let ((id-1 exp-1))
(let ((id-2 exp-2))
...
(let ((id-m exp-m))
exp-m+1
...
exp-n) ... ))
This means that, a reference to `id-1`

in
`exp-2`

will evaluate to the result of `exp-1`

.
Here are some examples to help illustrate the difference:
user> (let* ((x (+ 1 2)) (y ticks-per-second))
(+ (* x x x) (* y y)))
1000027.00000000
user> (let* ((x (+ 1 2)) (ticks-per-second 5) (y ticks-per-second))
(+ (* x x x) (* y y)))
52
user> (let ((x (+ 1 2)) (ticks-per-second 5) (y ticks-per-second))
(+ (* x x x)(* y y)))
1000027.00000000
In the first example, we have replaced `let`

by
`let*`

and the result is the same as it was before. However, if
we introduce a binding of `ticks-per-second`

to the value
`5`

, this affects the value of `y`

. In the third
example, we replace the `let*`

of the second example, then the
initial value of `y`

is that of `ticks-per-second`

in the enclosing lexical scope of the `let`

expression and the
result is that we got in the previous set of examples.

Julian Padget, jap@maths.bath.ac.uk, this version December 9, 1994