# Laboratory: Naming Values with Local Bindings

Summary: In this laboratory, you will ground your understanding of the basic techniques for locally naming values and procedures in Scheme, `let` and `let*`.

## Preparation

a. In the interactions pane, create a new 20x20 image. Make a note of the number of the image.

````>` `(image-show (image-new 20 20))`
```

b. Zoom in to at least 800%.

c. In the definitions pane, write a definition that associates the name `canvas` with that number. For example, if the image you created had the number 1, you would write

```(define canvas 1)
```

d. Click .

## Exercises

### Exercise 1: Evaluating `let`

What are the values of the following `let`-expressions? You may use MediaScheme to help you answer these questions, but be sure you can explain how it arrived at its answers.

a.

```(let ((tone "fa")
(call-me "al"))
(string-append call-me tone "l" tone))
```

b.

```(let ((total (+ 8 3 4 2 7)))
(let ((mean (/ total 5)))
(* mean mean)))
```

c.

```(let ((inches-per-foot 12)
(feet-per-mile 5280.0))
(let ((inches-per-mile (* inches-per-foot feet-per-mile)))
(* inches-per-mile inches-per-mile)))
```

### Exercise 2: Nesting Lets

a. Write a nested `let`-expression that binds a total of six names, `row`, `alpha`, `beta`, `gamma`, `delta`, and `epsilon`, with `row` bound to 0, `alpha` bound to `RGB-BLUE`, and each subsequent value to a redder version of of the previous name. That is, `beta` should be a a redder version of `alpha`, `gamma` a redder version of `beta`, and so on and so forth. The body of the innermost `let` should set five pixels of `canvas` to those colors.

Your result will look something like

```(let ((...))
(let ((...))
(let ((...))
(let ((...))
(let ((...))
(let ((...))
(image-set-pixel! canvas 0 row alpha)
(image-set-pixel! canvas 1 row beta)
(image-set-pixel! canvas 2 row gamma)
(image-set-pixel! canvas 3 row delta)
(image-set-pixel! canvas 4 row epsilon)))))))
```

b. Write a similar expression, this time with `row` bound to the value 1 and `alpha` bound to `RGB-BLACK`. The remaining names should still be bound to subsequently redder versions of `alpha`.

### Exercise 3: Simplifying Nested Lets

a. Write a `let*`-expression equivalent to the `let`-expression in the previous exercise, but using a different starting color and row.

b. Since we're repeating similar actions, it seems like setting five pixels to five shades of a color is a natural candidate for using `map` or `for-each`. Sketch what such a command would look like (don't use `let`), and compare and contrast the two solutions.

When you are done, you may want to read the notes on this problem.

### Exercise 4: Global vs. Local

Consider the following expression, which is a potential solution to the previous problem.

```(let* ((row 3)
(alpha RGB-GRAY)
(beta (rgb-redder alpha))
(gamma (rgb-redder beta))
(delta (rgb-redder gamma))
(epsilon (rgb-redder delta)))
(image-set-pixel! canvas 0 row alpha)
(image-set-pixel! canvas 1 row beta)
(image-set-pixel! canvas 2 row gamma)
(image-set-pixel! canvas 3 row delta)
(image-set-pixel! canvas 4 row epsilon))
```

a. What do you expect to have happen if we add the following definition before evalating that expression?

```(define RGB-GRAY (rgb-new 0 255 0))
```

c. Click to restore the value of gray.

d. What do you expect to have happen if we add the following definition before evaluating the `let*` expression?

```(define rgb-redder
(lambda (rgb)
(rgb-new (- (rgb-red rgb) 32)
(- (rgb-green rgb) 32)
(+ (rgb-blue rgb) 32))))
```

f. Comment out or delete your definition of `rgb-redder` and click to restore the value of `rgb-redder`.

g. Suggest a way that we might avoid the kind of problem you just encountered.

h. What do you expect to have happen if we add the following definition before evaluating the `let*` expression?

```(define + -)
```

j. Comment out or delete your definition of `+` and click to restore the value of `+`.

### Exercise 5: Detour: Printing Values

Sometimes it's useful to see values as they are being computed. Here's a procedure that makes it easy to tell when an expression is being used. It prints the value it is called with and then returns the value.

```(define value
(lambda (val)
(display "Computed: ")
(display val)
(newline)
val))
```

a. What do you expect to happen when you execute the following command?

```(+ (value 5) (value 7))
```

c. What do you expect to happen when you execute the following command?

```(* (value (+ (value 2) (value 3))) (value (+ (value 1) (value 1))))
```

e. What do you expect to happen when you execute the following command?

```(define tmp (value (* 3 4 5)))
```

### Exercise 6: Ordering Bindings

In the reading, we noted that it is possible to move bindings outside of the lambda in a procedure definition. In particular, we noted that the first of the two following versions of `years-to-seconds` required recomputation of `seconds-per-year` every time it was called while the second required that computation only once.

```(define years-to-seconds
(lambda (years)
(let* ((days-per-year 365.24)
(hours-per-day 24)
(minutes-per-hour 60)
(seconds-per-minute 60)
(seconds-per-year (* days-per-year hours-per-day
minutes-per-hour seconds-per-minute)))
(* years seconds-per-year))))

(define years-to-seconds
(let* ((days-per-year 365.24)
(hours-per-day 24)
(minutes-per-hour 60)
(seconds-per-minute 60)
(seconds-per-year (* days-per-year hours-per-day
minutes-per-hour seconds-per-minute)))
(lambda (years)
(* years seconds-per-year))))
```

a. Rename the first version `years-to-seconds-a` and the second `years-to-seconds-b`.

b. Using `value`, confirm that `years-to-seconds-a` does, in fact, recompute the values each time it is called. You might, for example, replace

```           (seconds-per-year (* days-per-year hours-per-day
minutes-per-hour seconds-per-minute)))
```

with

```           (seconds-per-year (value (* days-per-year hours-per-day
minutes-per-hour seconds-per-minute))))
```

c. Confirm that `years-to-seconds-b` does not recompute the values each time it is called. Again, make changes like those reported above.

d. Given that `years-to-seconds-b` does not recompute each time, when does it do the computation? (Consider when you see the messages.)

### Exercise 7: Ordering Bindings, Revisited

You may recall that we defined a procedure to compute a grey with the same brightness as a given color.

```(define rgb-greyscale
(lambda (color)
(let ((component (+ (* 0.30 (rgb-red color))
(* 0.59 (rgb-green color))
(* 0.11 (rgb-blue color)))))
(rgb-new component component component))))
```

You might be tempted to move the `let` clause outside the lambda, just as we did in the previous exercise. However, as we noted in this reading, this reordering will fail.

a. Verify that it will not work to move the `let` before the lambda, as in

```(define rgb-greyscale
(let ((brightness (+ (* 0.30 (rgb-red color))
(* 0.59 (rgb-green color))
(* 0.11 (rgb-blue color)))))
(lambda (color)
(rgb-new brightness brightness brightness))))
```

b. Explain, in your own words, why this fails (and why it should fail).

## For Those With Extra Time

If you find that you have some extra time, you can try any or all of these procedures, in any order you prefer.

### Extra 1: Binding Transformations

Some programmers find anonymous procedures a bit too anonymous. Hence, even when they only want to use a procedure once, they still name it. However, because they want to limit the impact of creating that procedure (e.g., they don't want to conflict with someone else's procedure with a similar name), because they don't want to bother writing the six-P documentation, or because they find their code is more readable if they name procedures, they write a local definition.

For example, here's an alternate way to transform an image by dropping all but the green component.

````>` ```(let ((only-green
(lambda (rgb)
(rgb-new 0 (rgb-green rgb) 0))))
(image-show (image-variant picture only-green)))```
```

a. Load an image of your choice and call it `picture`.

b. Verify that the code above works as described.

c. Write a similar expression that computes a variant in which the blue component of each pixel is 255 minus the blue component of the corresponding pixel in the original.

### Extra 2: Combining Drawings

Consider the following procedure

```(define drawing-munge
(lambda (drawing)
(let ((d0 drawing))
(let ((d1 (drawing-hshift d0 5)))
(let ((d2 (drawing-hshift d1 5)))
(let ((d3 (drawing-hshift d2 5)))
(let ((d4 (drawing-hshift d3 5)))
(let ((d5 (drawing-hshift d4 5)))
(drawing-group d0 d1 d2 d3 d4 d5)))))))))
```

a. Explain, in your own words, what `drawing-munge` does.

## Notes on the Exercises

### Notes on Exercise 3

a. Here's the form of answer we expected.

```(let* ((row 3)
(alpha RGB-GRAY)
(beta (rgb-redder alpha))
(gamma (rgb-redder beta))
(delta (rgb-redder gamma))
(epsilon (rgb-redder delta)))
(image-set-pixel! canvas 0 row alpha)
(image-set-pixel! canvas 1 row beta)
(image-set-pixel! canvas 2 row gamma)
(image-set-pixel! canvas 3 row delta)
(image-set-pixel! canvas 4 row epsilon))
```

b. The problem is relatively simple if we just want to set each pixel to the same color. To set row 6, we can use

```(for-each (lambda (col) (image-set-pixel! canvas col 6 RGB-GRAY))
(iota 5))
```

But how do we deal with the issue that we want each pixel a different color? We could start by making the list of colors one of the parameters to the `for-each`.

```(for-each (lambda (col rgb) (image-set-pixel! canvas col 6 rgb))
(iota 5)
(list alpha beta gamma delta epsilon))
```

Now we need to figure out how to get those five colors. We could write the expressions explicitly.

```(for-each (lambda (col rgb) (image-set-pixel! canvas col 6 rgb))
(iota 5)
(list
RGB-GRAY
(rgb-redder RGB-GRAY)
(rgb-redder (rgb-redder RGB-GRAY))
(rgb-redder (rgb-redder (rgb-redder RGB-GRAY)))
(rgb-redder (rgb-redder (rgb-redder (rgb-redder RGB-GRAY))))))
```

Hmmm ... that's almost as long as the original. It's also slightly less readable. Worst of all, it's much less efficient: ten calls to `rgb-redder` rather than four.

So, what should we do? We can stick with the original `let` expression. We can build a hybrid expression (one in which we generate the colors using a `let*` and then show them with `for-each`).

```(let* ((row 6)
(alpha RGB-GRAY)
(beta (rgb-redder alpha))
(gamma (rgb-redder beta))
(delta (rgb-redder gamma))
(epsilon (rgb-redder delta)))
(for-each (lambda (col rgb) (image-set-pixel! canvas col row rgb))
(iota 5)
(list alpha beta gamma delta epsilon)))
```

Perhaps we can find a more creative way to make the sequence of colored pixels. We'll leave that last technique to your imagination.

Samuel A. Rebelsky, rebelsky@grinnell.edu

Copyright (c) 2007-10 Janet Davis, Matthew Kluber, Samuel A. Rebelsky, and Jerod Weinman. (Selected materials copyright by John David Stone and Henry Walker and used by permission.)

This material is based upon work partially supported by the National Science Foundation under Grant No. CCLI-0633090. Any opinions, findings, and conclusions or recommendations expressed in this material are those of the author(s) and do not necessarily reflect the views of the National Science Foundation.

This work is licensed under a Creative Commons Attribution-NonCommercial 2.5 License. To view a copy of this license, visit `http://creativecommons.org/licenses/by-nc/2.5/` or send a letter to Creative Commons, 543 Howard Street, 5th Floor, San Francisco, California, 94105, USA.