Functional Problem Solving (CSC 151 2014S) : Labs
Primary: [Front Door] [Schedule] - [Academic Honesty] [Disabilities] [Email] - [FAQ] [Teaching & Learning] [Grading] [Rubric] - [Calendar]
Current: [Assignment] [EBoard] [Lab] [Outline] [Partners] [Reading]
Sections: [Assignments] [EBoards] [Examples] [Handouts] [Labs] [Outlines] [Partners] [Readings]
Reference: [Setup] - [Functions A-Z] [Functions By Topic] - [Racket] [Scheme Report (R5RS)] [R6RS] [TSPL4]
Related Courses: [Davis (2013F)] [Rebelsky (2010S)] [Rebelsky (2013F)] [Weinman (2012F)] [Weinman (2014S)]
Misc: [SamR] [Glimmer Labs] [CS@Grinnell] [Grinnell] [Issue Tracker (Course)]
Summary:
In this laboratory, you will ground your understanding of the basic
techniques for locally naming values and procedures in Scheme,
let and let*.
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)))
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
(irgb 0 0 255), 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
(define canvas (image-new 10 10))
(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)))))))
(image-show canvas)
b. Write a similar expression, this time with row
bound to the value 1 and alpha bound to
(irgb 0 0 0). The remaining names should still be bound
to subsequently redder versions of alpha.
a. Write a let*-expression equivalent to the
let-expression in the previous exercise, but using a
different starting color and row.
Consider the following expression, which is a potential solution to the previous problem.
(define canvas (image-new 20 20))
(define RGB-GRAY (irgb 128 128 128))
(define redder
(lambda (rgb)
(irgb (+ (irgb-red rgb) 32)
(irgb-green rgb)
(irgb-blue rgb))))
(let* ([row 3]
[alpha RGB-GRAY]
[beta (redder alpha)]
[gamma (redder beta)]
[delta (redder gamma)]
[epsilon (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))
(image-show canvas)
a. What do you expect to have happen if we change the definition of
RGB-GRAY as follows before evalating the
let expression?
(define RGB-GRAY (rgb-new 0 255 0))
b. Check your answer experimentally.
c. Restore the value of RGB-GRAY to 128/128/128.
d. What do you expect to have happen if we change the definition
of redder as follows
before evaluating the let* expression?
(define redder
(lambda (rgb)
(rgb-new (- (irgb-red rgb) 32)
(- (irgb-green rgb) 32)
(+ (irgb-blue rgb) 32))))
e. Check your answer experimentally.
f. Restore the old definition of redder.
g. Suggest a way that we might avoid the kind of problem you just encountered.
Recall that 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 evaluated. 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))
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)))
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.)
You may recall that we defined a procedure to compute a grey with the same brightness as a given color.
(define irgb-greyscale
(lambda (color)
(let ([component (+ (* 0.30 (irgb-red color))
(* 0.59 (irgb-green color))
(* 0.11 (irgb-blue color)))])
(irgb 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 irgb-greyscale
(let ([component (+ (* 0.30 (irgb-red color))
(* 0.59 (irgb-green color))
(* 0.11 (irgb-blue color)))])
(lambda (color)
(irgb component component component))))
b. Explain, in your own words, why this fails (and why it should fail).
If you find that you have some extra time, you can try any or all of these problems, in any order you prefer.
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 (color) (irgb 0 (irgb-green color) 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.
Consider the following procedure
(define drawing-munge
(lambda (drawing)
(let ([d0 drawing)]
(let ([d1 (hshift-drawing 5 d0))]
(let ([d2 (hshift-drawing 5 d1))]
(let ([d3 (hshift-drawing 5 d2))]
(let ([d4 (hshift-drawing 5 d3))]
(let ([d5 (hshift-drawing 5 d4))]
(drawing-group d0 d1 d2 d3 d4 d5)))))))))
a. Explain, in your own words, what drawing-munge
does.
b. Check your answer experimentally.
c. rewrite the expression to be more concise.
let or let* to name
the image and any other values that are used repeatedly.
a. Here's the form of answer we expected.
(define canvas (image-new 20 20))
(let* ([row 3]
[alpha RGB-GRAY]
[beta (redder alpha)]
[gamma (redder beta)]
[delta (redder gamma)]
[epsilon (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))
(image-show canvas)
Primary: [Front Door] [Schedule] - [Academic Honesty] [Disabilities] [Email] - [FAQ] [Teaching & Learning] [Grading] [Rubric] - [Calendar]
Current: [Assignment] [EBoard] [Lab] [Outline] [Partners] [Reading]
Sections: [Assignments] [EBoards] [Examples] [Handouts] [Labs] [Outlines] [Partners] [Readings]
Reference: [Setup] - [Functions A-Z] [Functions By Topic] - [Racket] [Scheme Report (R5RS)] [R6RS] [TSPL4]
Related Courses: [Davis (2013F)] [Rebelsky (2010S)] [Rebelsky (2013F)] [Weinman (2012F)] [Weinman (2014S)]
Misc: [SamR] [Glimmer Labs] [CS@Grinnell] [Grinnell] [Issue Tracker (Course)]
Samuel A. Rebelsky, rebelsky@grinnell.edu
Copyright (c) 2007-2014 Janet Davis, Samuel A. Rebelsky, and Jerod Weinman. (Selected materials are copyright by John David Stone or Henry Walker and are used with permission.)

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