Fundamentals of Computer Science I: Media Computing (CS151.02 2007F)
[Skip to Body]
Primary:
[Front Door]
[Glance]
-
[Academic Honesty]
[Instructions]
Current:
[Outline]
[EBoard]
[Reading]
[Lab]
[Assignment]
Groupings:
[Assignments]
[EBoards]
[Examples]
[Exams]
[Handouts]
[Labs]
[Outlines]
[Projects]
[Readings]
[Reference]
Reference:
[Scheme Report (R5RS)]
[Scheme Reference]
[DrScheme Manual]
Related Courses:
[CSC151.01 2007F (Davis)]
[CSC151 2007S (Rebelsky)]
[CSCS151 2005S (Stone)]
This lab is also available in PDF.
Summary: In this laboratory, you will ground your
understanding of the basic techniques for naming values and procedures
in Scheme, let and let*.
Contents:
Create a new 20x20 image and name it canvas.
let
What are the values of the following let-expressions?
You may use DrScheme 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"))
(list 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)))
a. Write a nested let-expression that binds a total of
five names, alpha, beta, gamma,
delta, and epsilon, with alpha
bound to a color of your choice (such as color.red),
and each subsequent name bound to a value darker than it (computed by
rgb.darker). That is, beta should be a darker
version of alpha, gamma a darker version of
beta, and so on and so forth. The body of the innermost
let should list the five colors.
Your result will look something like
(let ((...))
(let ((...))
(let ((...))
(let ((...))
(let ((...))
(list alpha beta gamma delta epsilon))))))
Remember that (rgb.darker color) gives a darker version
of color.
b. Name the result of the computation using define.
(define colors
(let ((...))
(let ((...))
(let ((...))
(let ((...))
(let ((...))
(list alpha beta gamma delta epsilon)))))))
c. Look at the values in that list with
> (map rgb->string colors)
d. Put some colors in canvas with
(region.compute-pixels!
canvas
0 0
(- (image.width canvas) 1) (- (image.height canvas) 1)
(lambda (pos) (list-ref colors
(modulo (* (position.col pos) (position.row pos))
5))))
a. Write a let*-expression equivalent to the
let-expression in the previous exercise, but using a
different starting color.
b. Repeat steps b and c of the previous problem.
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-a
(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-b
(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))))
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. 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))))
b. Confirm that years-to-seconds-b does not recompute the
values each time it is called. Again, make changes like those reported above.
c. Given that years-to-seconds-b does not recompute each
time, when does it do the computation? (Consider when you see the
messages.)
You may recall that we defined a procedure to compute a grey with the same brightness as a original color.
(define rgb.greyscale
(lambda (color)
(let ((brightness (+ (* 0.30 (rgb.red color))
(* 0.59 (rgb.green color))
(* 0.11 (rgb.blue color)))))
(rgb.new brightness brightness brightness))))
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).
Here's a procedure that one might use to make a blend between two colors.
(define image.fill-with-blend!
(lambda (image start-color end-color)
(region.compute-pixels!
image
0 0
(- (image.width image) 1) (- (image.height image) 1)
(lambda (pos)
(rgb.new (+ (* (position.col pos)
(/ 1 (- (image.width image) 1))
(rgb.red end-color))
(* (- (image.width image) (position.col pos) 1)
(/ 1 (- (image.width image) 1))
(rgb.red start-color)))
(+ (* (position.col pos)
(/ 1 (- (image.width image) 1))
(rgb.green end-color))
(* (- (image.width image) (position.col pos) 1)
(/ 1 (- (image.width image) 1))
(rgb.green start-color)))
(+ (* (position.col pos)
(/ 1 (- (image.width image) 1))
(rgb.blue end-color))
(* (- (image.width image) (position.col pos) 1)
(/ 1 (- (image.width image) 1))
(rgb.blue start-color))))))))
a. Create a blend from magenta to yellow in a five-by-five image. Then, find the largest square image you can fill with a blend from magenta to yellow in under fifteen seconds. (You need not get an exact size, just a close approximation.)
b. Identify common expressions that are repeated in image.fill-with-blend!. When you are done,
compare your list to those in the notes on
this part of the problem.
c. Which of these common expressions have values that are independent of the position?
d. Write a let or let* expression to bind names
to these expressions. Make sure that this let encloses
the call to region.compute-pixels!.
When you are done, compare your answer to the notes on this part of the problem.
e. Run the modified code on a five-by-five image to see if it appears to be any faster. Then, find the largest square image you can fill with a blend from magenta to yellow in under fifteen seconds. (Again, you need not get an exact size, just a reasonable approximation.)
f. Which of the common expressions from step b have values that depend on the position?
g. Write a let or let* expression to bind names
to those pieces of code. For example, since (position.col pos)
appears three times, you might name it col.
When you are done, compare your answer to the notes on this part of the problem.
h. Run the modified code on the same image size as you came up with for step e see if it appears to be any faster.
i. There are a few expressions, such as (rgb.red end-color),
that appear only once, but that have an identical value each time the inner
lambda is applied. Name those expressions in the outer let.
j. Compare your final version to the notes on this part of the problem.
k. What advantages do you see to this final version?
Here is a procedure that takes a non-empty list of spots as an argument, and returns the leftmost spot in the list (or one of the leftmost spots, if there is a tie).
;;; Procedure:
;;; spots.leftmost
;;; Parameters:
;;; spots, a list of spots
;;; Purpose:
;;; Finds the leftmost of spots.
;;; Produces:
;;; leftmost, a spot
;;; Preconditions:
;;; spots is nonempty.
;;; Postconditions:
;;; leftmost is an element of spots.
;;; For every spot, spot, in spots
;;; (spot.col leftmost) <= (spot.col spot)
(define spots.leftmost
(lambda (spots)
(if (null? (cdr spots))
(car spots)
(spot.leftmost (car spots) (spots.leftmost (cdr spots))))))
The definition of spots.leftmost includes a call to the
spot.leftmost procedure, which returns the leftmost of
two spots.
;;; Procedure:
;;; spot.leftmost
;;; Parameters:
;;; spot1, a spot
;;; spot2, a spot
;;; Purpose:
;;; Finds the leftmost of the two spots.
;;; Produces:
;;; leftmost, a spot
;;; Preconditions:
;;; [No additional preconditions.]
;;; Postconditions:
;;; leftmost is spot1 or spot2.
;;; (spot.col leftmost) <= (spot.col spot1)
;;; (spot.col leftmost) <= (spot.col spot2)
(define spot.leftmost
(lambda (spot1 spot2)
(if (<= (spot.col spot1) (spot.col spot2))
spot1
spot2)))
Using a let expression, revise the definition of
spots.leftmost so that the name spot.leftmost
is bound to the procedure that it denotes only locally.
Note that there are two ways to do the previous problem. You can nest the
lambda within the let, as in
(define spots.leftmost
(let (...)
(lambda (spots)
...)))
or you can nest the let within th elambda, as in
(define spots.leftmost
(lambda (spots)
(let (...)
...)))
a. Define spots.leftmost in whichever way that you did not define it for the previous exercise.
b. Does the order of nesting affect what happens when the procedure is invoked?
c. If there is a difference, which arrangement is better? Why?
Here are some duplicated expressions. You may have noted others.
(- (image.width image) 1)
(position.col pos)
(position.row pos)
(/ 1 (- (image.width image) 1))
(- width (position.col pos) 1)
The following expressions are not duplicated. Nonetheless, you will find it useful to name them. You will be asked to do so in a later step of this exercise.
(rgb.red start-color)
(rgb.red end-color)
(rgb.green start-color)
(rgb.green end-color)
(rgb.blue start-color)
(rgb.blue end-color)
(define image.fill-with-blend!
(lambda (image start-color end-color)
(let* ((width (image.width image))
(last-col (- width 1))
(frac (/ 1 last-col)))
(region.compute-pixels!
image
0 0
last-col (- (image.height image) 1)
(lambda (pos)
(rgb.new (+ (* (position.col pos)
frac
(rgb.red end-color))
(* (- width (position.col pos) 1)
frac
(rgb.red start-color)))
(+ (* (position.col pos)
frac
(rgb.green end-color))
(* (- width (position.col pos) 1)
frac
(rgb.green start-color)))
(+ (* (position.col pos)
frac
(rgb.blue end-color))
(* (- width (position.col pos) 1)
frac
(rgb.blue start-color)))))))))
(define image.fill-with-blend!
(lambda (image start-color end-color)
(let* ((width (image.width image))
(last-col (- width 1))
(frac (/ 1 last-col)))
(region.compute-pixels!
image
0 0
last-col (- (image.height image) 1)
(lambda (pos)
(let* ((col (position.col pos))
(loc (- width col 1)))
(rgb.new (+ (* col frac (rgb.red end-color))
(* loc frac (rgb.red start-color)))
(+ (* col frac (rgb.green end-color))
(* loc frac (rgb.green start-color)))
(+ (* col frac (rgb.blue end-color))
(* loc frac (rgb.blue start-color))))))))))
(define image.fill-with-blend!
(lambda (image start-color end-color)
(let* ((width (image.width image))
(last-col (- width 1))
(frac (/ 1 last-col))
(start-red (rgb.red start-color))
(end-red (rgb.red end-color))
(start-green (rgb.green start-color))
(end-green (rgb.green end-color))
(start-blue (rgb.blue start-color))
(end-blue (rgb.blue end-color)))
(region.compute-pixels!
image
0 0
last-col (- (image.height image) 1)
(lambda (pos)
(let* ((col (position.col pos))
(loc (- width col 1)))
(rgb.new (+ (* col frac end-red)
(* loc frac start-red))
(+ (* col frac end-green)
(* loc frac start-green))
(+ (* col frac end-blue)
(* loc frac start-blue)))))))))
http://www.cs.grinnell.edu/~rebelsky/Courses/CS151/History/Labs/let.html.
[Skip to Body]
Primary:
[Front Door]
[Glance]
-
[Academic Honesty]
[Instructions]
Current:
[Outline]
[EBoard]
[Reading]
[Lab]
[Assignment]
Groupings:
[Assignments]
[EBoards]
[Examples]
[Exams]
[Handouts]
[Labs]
[Outlines]
[Projects]
[Readings]
[Reference]
Reference:
[Scheme Report (R5RS)]
[Scheme Reference]
[DrScheme Manual]
Related Courses:
[CSC151.01 2007F (Davis)]
[CSC151 2007S (Rebelsky)]
[CSCS151 2005S (Stone)]
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 Mon Dec 3 09:55:04 2007.
The source to the document was last modified on Tue Oct 16 11:51:42 2007.
This document may be found at http://www.cs.grinnell.edu/~rebelsky/Courses/CS151/2007F/Labs/let-lab.html.
You may wish to
validate this document's HTML
;
;
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.