# Class 22: Local Bindings

Back to Preconditions and Postconditions. On to Laboratory: Local Bindings.

Held: Tuesday, 25 February 2003

Summary: Today we consider how to bind names to values using Scheme's `let` expressions.

Related Pages:

Notes:

• Are there questions on exam 1?

Overview:

• Why name things.
• Naming things with `let`.
• Naming things with `let*`.
• Naming procedures.

## The Problem: Naming Values

• As we've seen in many problems, it helps to name the values that we use within our procedure. Why?
• It can make the code more readable because the name tells us something about the role the value plays.
• It can make the code more efficient, because it allows us to avoid recomputing a value.
• Consider the inefficient but elegant `closest-to-zero`
```(define closest-to-zero
(lambda (lst)
(cond
; If there's only one element in the list, it's closest to zero
((null? (cdr lst)) (car lst))
; If the current element is closer to zero than the closest
; remaining thing, use that
((< (abs (car lst)) (abs (closest-to-zero (cdr lst))))
(car lst))
; Otherwise, use the thing in the remainder closest to zero
(else (closest-to-zero (cdr lst))))))
```
• Instead of making two calls to `closest-to-zero`, we can make one by naming the result and using it twice. One possibility is to use a helper procedure
```(define closest-to-zero
(lambda (lst)
(cond
((null? (cdr lst)) (car lst))
(closer-to-zero (car lst) (closest-to-zero (cdr lst))))))

(define closer-to-zero
(lambda (guess1 guess2)
(if (< (abs guess1) (abs guess2)) guess1 guess2)))
```
• Another possiblity is to name the result of the recursive computation.
```(define closest-to-zero
(lambda (lst)
(cond
((null? (cdr lst)) (car lst))
"Compute (closest-to-zero (cdr lst)) and call it guess"
(if (< (abs (car lst)) (abs guess)) (car lst) guess))))
```
• Another reasons to name things is that we might want to create helper procedures and only make them available to the current procedure.

## Naming Things with `let`

• You name things with `let`.
• `let` has the form
```(let ((name1 exp1)
(name2 exp2)
...
(namen expn))
body)
```
• `let` has the meaning:
• Evaluate all the expressions.
• Update the binding table to associate each name with the corresponding value.
• Evaluate body using the updated binding table.
• Eliminate all the bindings just created.
• You can use `let` in a simple expression:
```(define values (list 1 4 2 4 1 5 9))
(let ((largest (max values))
(smallest (min values)))
(/ (+ largest smallest) 2))
```
• More frequently, we use `let` within a procedure. Here's a new version of `closest-to-zero` that uses `let`.
```(define closest-to-zero
(lambda (lst)
; If there's only one element in the list, it's closest to zero
(if (null? (cdr lst)) (car lst)
; Otherwise, find the remaining element closest to zero and
; call it guess
(let ((guess (closest-to-zero (cdr lst))))
; Choose the closer to zero of the first element and guess
(if (< (abs (car lst)) (abs guess)) (car lst) guess)))))
```

## Sequencing Bindings with `let*`

• If we want to bind some things in sequence, we need to use `let*` rather than `let`.
• `let*` has the form
```(let* ((name1 exp1)
(name2 exp2)
...
(namen expn))
body)
```
• `let*` has the meaning:
• Evaluate exp1.
• Update the binding table to associate name1 with that value.
• Evaluate exp2.
• Update the binding table to associate name2 with that value.
• ...
• Evaluate expn.
• Update the binding table to associate namen with that value.
• Evaluate body using the updated binding table.
• Eliminate all the bindings just created.

## Naming Helper Procedures

• You can also use this technique to name helper procedures. However, it does not work for recursive helper procedures.
• Here's an example of the use of a non-recursive helper procedure that checks whether a value of any type is exact
```;;; Procedure:
;;;   exact-average
;;; Parameters:
;;;   num1, an exact number
;;;   num2, an exact number
;;; Purpose:
;;;   Average the two numbers.
;;; Produces:
;;;   average, an exact number
;;; Preconditions:
;;;   num1 is an exact number [Verified]
;;;   num2 is an exact number [Verified]
;;; Postconditions:
;;;   Guess.
(define exact-average
(lambda (num1 num2)
(let ((verify?
(lambda (val) (and (number? val) (exact? val)))))
(cond
((not (verify? num1))
(error "exact-average" "first parameter is a non-number"))
((not (verify? num2))
(error "exact-average" "second parameter is a non-number"))
(else (/ (+ num1 num2) 2))))))
```

## History

Thursday, 16 January 2003 [Samuel A. Rebelsky]

• First version, created mostly automatically from previous course.

Back to Preconditions and Postconditions. On to Laboratory: Local Bindings.

Disclaimer: I usually create these pages on the fly, which means that I rarely proofread them and they may contain bad grammar and incorrect details. It also means that I tend to update them regularly (see the history for more details). Feel free to contact me with any suggestions for changes.

This document was generated by Siteweaver on Tue May 6 09:29:52 2003.
The source to the document was last modified on Thu Jan 16 13:45:58 2003.
This document may be found at `http://www.cs.grinnell.edu/~rebelsky/Courses/CS151/2003S/Outlines/outline.22.html`.

You may wish to validate this document's HTML ; ; Check with Bobby

Samuel A. Rebelsky, rebelsky@grinnell.edu