Held Thursday, March 15, 2001
Today we investigate higher-order procedures; procedures that take other
procedures as parameters or return procedures as values.
- Yes, we will have class tomorrow (even though I'm leaving for London
- I'd like you to try to do (or at least scan) two readings tonight:
- I saw three ways that people wrote the
procedure from yesterday's lab. They seem to be good examples for
discussing some tradeoffs in program design.
(let ((last-element (lambda (lst)
(car (reverse lst)))))
(let ((last-element (lambda (lst)
(list-ref lst (- (length lst) 1)))))
(letrec ((last-element (lambda (lst)
(if (null? (cdr lst))
(last-element (cdr lst))))))
- Design patterns, revisited
- A problem: Applying a procedure to all values in a list
- A key technique: Procedures as parameters
- Common higher-order procedures:
- Another key technique: Anonymous procedures
- A final key technique: Procedures as return values
- As I've mentioned earlier, the more you proram, the more you find that
there are many problems whose solutions have similar structures.
- We might then want to look more abstractly at those structures and
see what kinds of problems they apply to.
- These solution structures are typically called patterns
or design patterns.
- In some languages, patterns are simply a guide to the programmer,
giving techniques for designing solutions.
- In Scheme, you can actually encode many patterns in procedures.
- Today we'll consider a few examples of design patterns (typically
involving recursion) and see how they might be coded.
- We'll also learn about some related issues: procedures as values
and anonymous procedures.
- Let's start with two similar problems, both of which somone might use
to process a list of grades.
- Add 5 to every value in a list of numbers.
- Multiply every value in a list of numbers by 10/8.
- How might we code these?
- Can we generalize? Certainly
- As you may have noted, this seems a little bit inelegant.
- What else can we do?
- We can take the procedure to apply to each value as a parameter
to the general procedure!
- Note that the
apply to all design pattern is so common that
Scheme includes it as a built-in procedure (called
(map proc lst): what we just wrote.
(apply proc lst): a way to treat
the elements of lst as parameters to proc.
(define sum (lambda (lst) (apply + lst)))
- When we use higher-order procedures, we often have to build small
helpers that say what to do. For example, consider
> (let ((square (lambda (x) (* x x))))
(map square (list 1 2 3 4)))
- But what does this say? It tells us that
another name for
(lambda (x) (* x x)) and then uses
- When we use the name, Scheme simply substitutes the thing that's
- We can do the substitution ourselves
(map (lambda (x) (* x x)) '(1 2 3 4))
- We've used a procedure without naming it!
- Such unnamed procedures are called anonymous procedures.
You'll find that we often use them in conjunction with design patterns.
- Extract all the elements of a list that meet some criteria.
- Generalization of sum and product?
- Given that we can take procedures as parameters, it may also make sense
to return procedures as values.
- What does a procedure value look like? It looks like
(lambda (arguments) body)
- So, here's a procedure that takes one parameter, a number, and
returns a procedure. The resultant procedure takes one parameter
and adds the first number to its parameter.
(lambda (v) (+ n v))))
- How did we build that? First we thought about the result. We wanted
a procedure of one parameter that added
some number to its
(lambda (v) (+ some-number v))
- Now, we want to build that value, filling in the some-number.
Friday, 12 January 2001
- Created generic outline format for class.
Thursday, 15 March 2001
- Filled in some details. Many taken from an earlier outline
and then rewritten.