Scheme’s variables have lexical scope, i.e., they are
visible only to forms within a certain contiguous
stretch of program text. The *global* variables we
have seen thus far are no exception: Their scope is all
program text, which is certainly contiguous.

We have also seen some examples of *local*
variables. These were the `lambda`

parameters, which
get *bound* each time the procedure is called, and
whose scope is that procedure’s body. E.g.,

(define x 9) (define add2 (lambda (x) (+ x 2))) x=>9 (add2 3)=>5 (add2 x)=>11 x=>9

Here, there is a global `x`

, and there is also a
local `x`

, the latter introduced by procedure
`add2`

. The global `x`

is always
`9`

. The local `x`

gets bound to `3`

in the
first call to `add2`

and to the value of the global
`x`

, i.e., `9`

, in the second call to `add2`

.
When the procedure calls return, the global `x`

continues to be `9`

.

The form `set!`

modifies the lexical binding of a
variable.

(set! x 20)

modifies the global binding of `x`

from `9`

to
`20`

, because that is the binding of `x`

that is
visible to `set!`

. If the `set!`

was inside
`add2`

’s body, it would have modified the local
`x`

:

(define add2 (lambda (x) (set! x (+ x 2)) x))

The `set!`

here adds `2`

to the local variable
`x`

, and the procedure returns this new value of the local `x`

. (In terms of effect,
this procedure is indistinguishable from the previous
`add2`

.) We can call `add2`

on the
global `x`

, as before:

(add2 x)=>22

(Remember global `x`

is now `20`

, not `9`

!)

The `set!`

inside `add2`

affects only the local
variable used by `add2`

. Although the local variable
`x`

got its binding from the global `x`

,
the latter is unaffected by the `set!`

to the local
`x`

.

x=>20

Note that we had all this discussion because we used
the same identifier for a local variable and a global
variable. In any text, an identifier named `x`

refers
to the lexically closest variable named `x`

. This
will *shadow* any outer or global `x`

’s. E.g.,
in `add2`

, the parameter `x`

shadows the global
`x`

.

A procedure’s body can access and modify variables in its surrounding scope provided the procedure’s parameters don’t shadow them. This can give some interesting programs. E.g.,

(define counter 0) (define bump-counter (lambda () (set! counter (+ counter 1)) counter))

The procedure `bump‑counter`

is a zero-argument
procedure (also called a *thunk*). It introduces
no local variables, and thus cannot shadow anything.
Each time it is called, it modifies the *global*
variable
`counter`

— it increments it by 1 — and returns
its current value. Here are some successive calls to
`bump‑counter`

:

(bump-counter)=>1 (bump-counter)=>2 (bump-counter)=>3

`let`

and `let*`

Local variables can be introduced without explicitly
creating a procedure. The special form `let`

introduces a list of local variables for use within its
body:

(let ((x 1) (y 2) (z 3)) (list x y z))=>(1 2 3)

As with `lambda`

, within the `let`

-body, the local
`x`

(bound to `1`

) shadows the global `x`

(which
is bound to `20`

).

The local variable initializations — `x`

to `1`

;
`y`

to `2`

; `z`

to `3`

— are not considered
part of the `let`

body. Therefore, a reference to
`x`

in the initialization will refer to the global,
not the local `x`

:

(let ((x 1) (y x)) (+ x y))=>21

This is because `x`

is bound to `1`

, and `y`

is
bound to the *global* `x`

, which is `20`

.

Sometimes, it is convenient to have `let`

’s list of
lexical variables be introduced in sequence, so that
the initialization of a later variable occurs in the
*lexical scope* of earlier variables. The form
`let*`

does this:

(let* ((x 1) (y x)) (+ x y))=>2

The `x`

in `y`

’s initialization refers to the `x`

just above. The example is entirely equivalent to —
and is in fact intended to be a convenient abbreviation
for — the following program with nested `let`

s:

(let ((x 1)) (let ((y x)) (+ x y)))=>2

The values bound to lexical variables can be procedures:

(let ((cons (lambda (x y) (+ x y)))) (cons 1 2))=>3

Inside this `let`

body, the lexical variable `cons`

adds its arguments. Outside, `cons`

continues to
create dotted pairs.

`fluid‑let`

A lexical variable is visible throughout its scope,
provided it isn’t shadowed. Sometimes, it is helpful
to *temporarily* set a lexical variable to a
certain value. For this, we use the form
`fluid‑let`

.^{1}

(fluid-let ((counter 99)) (display (bump-counter)) (newline) (display (bump-counter)) (newline) (display (bump-counter)) (newline))

This looks similar to a `let`

, but instead of
shadowing the global variable `counter`

, it
temporarily sets it to `99`

before continuing with
the
`fluid‑let`

body. Thus the `display`

s in the body
produce

100 101 102

After the `fluid‑let`

expression has evaluated,
the global `counter`

reverts to the value it had
before the `fluid‑let`

.

counter=>3

Note that `fluid‑let`

has an entirely different
effect from `let`

. `fluid‑let`

does not introduce
new lexical variables like `let`

does. It modifies
the bindings of *existing* lexical variables, and
the modification ceases as soon as the `fluid‑let`

does.

To drive home this point, consider the program

(let ((counter 99)) (display (bump-counter)) (newline) (display (bump-counter)) (newline) (display (bump-counter)) (newline))

which substitutes `let`

for `fluid‑let`

in
the previous example. The output is now

4 5 6

I.e., the global `counter`

, which is initially
`3`

, is updated by each call to `bump‑counter`

.
The new lexical variable `counter`

, with its
initialization of `99`

, has no impact on the calls to
`bump‑counter`

, because although the calls to
`bump‑counter`

are within the scope of this local
`counter`

, the body of `bump‑counter`

isn’t. The
latter continues to refer to the *global*
`counter`

, whose final value is `6`

.

counter=>6

We see that unlike `add2`

, the procedure `bump‑counter`

returns a different result each time it’s called, because it
side-effects something outside itself. One particularly useful
variant of this procedure generates a different *random*
number each time it’s called. Many Schemes provide this as a
primitive procedure called `random`

^{2}:
When called with no argument, `(random)`

returns a
“pseudorandom” number in the interval [0, 1), i.e., between 0
(inclusive) and 1 (exclusive), such that the results are
uniformly distributed within that interval.

(random)=>0.6360226737551197 (random)=>0.8057127493871963 (random)=>0.8595213305159558

With only a little bit of arithmetic, `random`

can be used
to simulate events of known probability. Consider the throwing of
a fair, six-headed die: The outcomes 1, 2, 3, 4, 5, 6 are equally
likely. To simulate this, we divide the interval [0, 1) into six
equal segments, associate each segment with an outcome, and have
`(random)`

’s output decide which outcome occurred. One way to
do it is to multiply the random number *n* (0 ≤*n* < 1) by 6
and take the ceiling: I’ll leave you to convince yourself that
this takes on the value of each die face with 1/6 probability.

(define throw-one-die (lambda () (let ((result (ceiling (* (random) 6)))) result)))

`throw‑two‑dice`

simply calls `throw‑one‑die`

twice:

(define throw-two-dice (lambda () (+ (throw-one-die) (throw-one-die))))

It returns an integer between 2 and 12 inclusive — not all equally likely!

^{1} `fluid‑let`

is a nonstandard special
form. See section 8.3 for a definition
of `fluid‑let`

in Scheme.

^{2} Writing your own version
of `random`

in Scheme requires quite a bit of mathematical
chops to get something acceptable. We won’t get into that here.