%CustomEntities; %CourseEntities; %CommonEntities; ]>
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. Create a new 20x20 image and name it canvas. Zoom in to at least 800%. b. Add the following definitions to your library. (define black (rgb-new 0 0 0)) (define white (rgb-new 255 255 255)) (define blue (rgb-new 0 0 255)) c. Load your library.
Exercises
Exercise 1: Evaluating <code>let</code> 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 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 black. The remaining names should still be bound to subsequently redder versions of alpha.
Exercise 3: Simplifying Nested Lets Write a let*-expression equivalent to the let-expression in the previous exercise, but using a different starting color and row.
Exercise 4: 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. a. What do you expect to happen when you execute the following command? (+ (value 5) (value 7)) b. Check your answer experimentally. c. What do you expect to happen when you execute the following command? (* (value (+ (value 2) (value 3))) (value (+ (value 1) (value 1)))) d. Check your answer experimentally. e. What do you expect to happen when you execute the following command? (define tmp (value (* 3 4 5)))
Exercise 5: 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. 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 6: Ordering Bindings, Revisited You may recall that we defined a procedure to compute a grey with the same brightness as a given color. 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. b. Check your answer experimentally.