# Local variables#

`let`

syntax#

In Defining variables, you met `define`

, which defines global variables. These
variables are called „global“ because they are available everywhere. The syntax
shown here, on the other hand, binds „local“ variables, which are only
temporarily valid in one section of the code. Here is a program that does not
work:

```
(define composer "Mozart")
(if (equal? composer "Mozart")
(begin
(define birth 1756)
(format #t
"Mozart was born in ~a, his 300th birthday will be in ~a."
birth
(+ birth 300))))
```

(NB: At least, this program will not work with Guile 2.2. The rules over the
placement of `define`

s are complex, have changed in the history of Guile, and
are still not stabilized.)

The reason this does not work is that `birth`

is defined as a top-level
variable, but its binding occurs in an expression, which is only evaluated under
certain conditions.

This is why `define`

is only useful at the top level, to define functions, or
constants such as

```
(define PI 3.1415926535)
```

For temporary variables which are no longer needed after the result has been
computed, a different syntax is used. It uses the `let`

keyword. Here is a
syntax diagram:

```
(let ((variable1 value1)
(variable2 value2)
(variable3 value3)
...)
expression1
expression2
...)
```

When `let`

is executed, the values are first evaluated and bound to all the
variables. Then, the expressions are evaluated in order, and the `let`

expression evaluates to the value of the last expression inside it, just like
with `begin`

. After the last parenthesis of `let`

has been closed, the variables
no longer exist. In technical terms, they are bound in the scope of the `let`

expression.

The following examples use the `random`

function. The call `(random n)`

return a
random integer between \(0\) and \(n - 1\). Of course, you might get different
results than the ones shown here, since they are random.

```
(define (loto)
(let ((x (random 2))
(y (random 2)))
(display
(if (and (= x 1)
(= y 1))
"Chance!"
"You lost!"))))
(loto)
⊨ You lost!
```

Here, two coins are flipped (heads = 0, tails = 1). If both show tails, the user wins.

A `let`

form has a recognizable visual shape:

```
(let (xxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxx)
xxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxx)
```

Scheme programmers, without ever counting parentheses, recognize the block of variables and the block of expressions.

Let’s invent a variant of the game, where a dice is first rolled, which gives the number of balls in a box, then one ball is drawn from the box at random, given that there is exactly one winning ball. For example, if the dice gives 4, there will be 4 balls in the box and thus a probability of 1/4 to win. It is tempting to write this:

```
(define (loto2)
(let ((number-of-balls (random 10))
(ball (random number-of-balls)))
(display
(if (equal? ball 0)
"Chance!"
"You lost."))))
```

Yet, this gives the error „Unbound variable: number-of-balls“. This is because
`let`

is actually quirky. First, the values for all variables are evaluated, and
only then, they are bound to the variables. The interpreter tries to evaluate
`(random 10)`

, then `(random number-of-balls)`

, and afterwards bind the
variables `number-of-balls`

and `ball`

to these two values. Of course, we would
like `number-of-balls`

to be bound before `(random number-of-balls)`

is
computed. In this case, `let`

needs to be replaced with a variant of it, `let*`

,
of which the syntax is exactly the same. The corrected example is:

```
(define (loto2)
(let* ((number-of-balls (random 10))
(ball (random number-of-balls)))
(display
(if (equal? ball 0)
"Chance!"
"You lost."))))
(loto2)
⊨ You lost.
```

Unlike `let`

, `let*`

first evaluates the first expression and stores it in the
first variable, and only then evaluates the expression (which can thus reuse the
first variable) and stores it in the second variable, etc.

In practice, you almost always want to use `let*`

.

## Parenthesizing a `let`

expression#

`let*`

expressions contain many parentheses. It is easy for the inexperienced to
get them wrong. This part goes through all common parenthesizing errors to
explain them. I will use this example:

```
(let ((a 5))
(+ a 15))
```

Forgetting a parenthesis.

(let ((a 5) ; missing ) (+ a 15))

With this expression in a LilyPond file (with a preceding

`#`

to introduce Scheme code), you will get the error „end of file“, which means that the Scheme expression never ended.Adding an extraneous parenthesis.

(let ((a 5)) (+ a 15))) ; extra )

In LilyPond (don’t forget the

`#`

), the error may seem more surprising: „syntax error, unexpected EVENT_IDENTIFIER“. What happens is that when the expression ends, LilyPond syntax is used again. At this point, the extraneous parenthesis is parsed. In LilyPond, parentheses are the syntax for slurs, hence the message indicating that a slur is not valid on the top level.Moving a parenthesis.

(let ((a 5) ; missing ) (+ a 15))) ; extra )

Here, there is no extraneous or missing parenthesis for the expression as a whole; its parentheses are balanced. Your text editor will thus not find the mistake. Yet, a parenthesis is misplaced. The error message is somewhat short: „bad let“. To understand it, let us come back to how a

`let`

is constructed:(let (xxxxxxxxx xxxxxxxxx) xxxxxxx xxxxxxx)

The first

`(...)`

contains all bindings. Here, this`(...)`

actually contains everything that’s inside the`let`

expression. The code could be reformatted like this:(let ((a 5) (+ a 15)) )

The interpreter tries to see

`(+ a 15)`

as`(variable-name value)`

, which fails because there are three elements between the parentheses rather than two. The`let`

is also missing a main expression after the bindings, hence „bad let“.Omitting parentheses.

(let (a 5) ; should be ((a 5)) (+ a 15))

Again, the interpreter complains about a „bad let“. To understand, let us remember that everything in the first

`(...)`

is taken as a sequence of bindings, taking the form`(variable-name value)`

. By reformatting the`let`

, the problem is made clear:(let ( a 5 ) (+ a 15))

Indeed,

`a`

and`5`

do not have the form`(variable-name value)`

. This is why you need two pairs of parentheses even to define just one variable:`((a 5))`

.

## Simplifying code with `let*`

#

`let*`

is a useful tool to make code more readable and understandable. For
demonstration purposes, this code is taken from LilyPond, and adapted to contain
no `let*`

at all.

```
(apply ly:stencil-add
(map
(lambda (stil accessor)
(ly:stencil-translate-axis
stil
(accessor
(coord-translate
(interval-widen
(ly:relative-group-extent
(apply append
(map
(lambda (g)
(cons g
(apply append
(map
(lambda (sym)
(cond
((ly:grob? (ly:grob-object g sym))
(list (ly:grob-object g sym)))
((ly:grob-array? (ly:grob-object g sym))
(ly:grob-array->list (ly:grob-object g sym)))
(else
'())))
(ly:grob-property g 'parenthesis-friends)))))
(ly:grob-array->list
(ly:grob-object grob 'elements))))
(ly:grob-system grob)
X)
(ly:grob-property grob 'padding 0.1))
(- (ly:grob-relative-coordinate grob
(ly:grob-system grob)
X))))
X))
(ly:grob-property grob 'stencils)
(list car cdr)))
```

If you understand nothing in this, you have taken the point. What makes this
code hard to read is endless nesting of expressions, which makes you lose track
of what is being done, just like if you were reading a single sentence several
pages long. Furthermore, the order of execution goes from inner expressions,
which are read last, to outer expressions, whereas for us humans it is easier to
think when the code executes linearly. Here is the same code rewritten to use
`let`

and `let*`

:

```
(let* ((elts (ly:grob-array->list (ly:grob-object grob 'elements)))
(get-friends
(lambda (g)
(let* ((syms (ly:grob-property g 'parenthesis-friends))
(get-friends-for-symbol
(lambda (sym)
(let ((friends (ly:grob-object g sym)))
(cond
((ly:grob? friends)
(list friends))
((ly:grob-array? friends)
(ly:grob-array->list friends))
(else
'())))))
(friend-lists (map get-friends-for-symbol syms))
(friends (apply append friend-lists)))
(cons g friends))))
(all-friend-lists (map get-friends elts))
(all-friends (apply append all-friend-lists))
(all-friends-array (ly:grob-list->grob-array all-friends))
(X-refp (ly:grob-common-refpoint-of-array grob all-friends-array X))
(my-X (ly:grob-relative-coordinate grob X-refp X))
(X-ext (ly:relative-group-extent all-friends-array X-refp X))
(padding (ly:grob-property grob 'padding 0.1))
(wide-X-ext (interval-widen X-ext padding))
(parenthesis-positions (coord-translate wide-X-ext (- my-X)))
(stencils (ly:grob-property grob 'stencils))
(left-paren (first stencils))
(right-paren (second stencils))
(translated-left-paren
(ly:stencil-translate-axis left-paren (interval-start parenthesis-positions) X))
(translated-right-paren
(ly:stencil-translate-axis right-paren (interval-end parenthesis-positions) X)))
(ly:stencil-add translated-left-paren translated-right-paren))
```

Without knowing anything about how LilyPond works internally, you can already
understand some things: the grobs encompassed by a pair of parentheses are read
(`elts`

), the list is extended so it comprises their „friends“ (`all-friends`

),
a horizontal reference point is computed (`X-refp`

), then a horizontal
coordinate (`my-X`

), etc.

It is easier to write complicated functions as a big `let*`

, where variables are
bound step-by-step, so that the final expression is simple and short. This
advice will be particularly useful while you are a beginner.