Outline 43: Higher-Order Procedures, Revisited
Held: Tuesday, 17 November 2015
Back to Outline 42 - Trees.
On to Outline 44 - Files in Scheme.
Summary
We revisit the topic of higher-order procedures, one of the most
important techniques in languages like Scheme. Higher-order procedures
are procedures -- like map, left-section, or compose -- that
take other procedures as parameters, return other procedures as values,
or both.
Related Pages
Overview
- Some program design principles.
- Thinking about repetition.
- Procedures as first-class values.
Administrivia
- Continue partners!
- Review sessions this week:
- Wednesday, 8pm (Caleb)
- Thursday, 10am (SamR)
- Thursday, 8pm (Erin)
Upcoming Work
- Projects: Next Tuesday at 10:00 a.m.
- No Reading for Friday!
- Today's Lab writeup (due Friday)
Extra Credit Opportunities
- If possible, send me these in advance.
- Note: You don't get extra credit for supporting yourself.
Academic
- Any visit to the current show in the Faulconer gallery.
- Learning Deconstructed Workshop Series, Tuesdays at 11 in JRC 209.
- Scholars' Convocation Thursday: Cosmic Secrets: Soviet Space Exploration,
Censorship, and the Cold War.
- Metropolitan Opera Simulcast, November 21, 11:30 a.m. Lulu by Berg,
Harris Cinema. (Warning! It's about four hours long.)
- Saturday Night's Silent Film + Live Score.
Peer Support
- Translations (a play). 7:30 p.m. Thursday through Saturday,
2:00 p.m. Sunday. Tickets at the Box Office.
Miscellaneous
- Noontime rally, Thursday, in support of the Missouri students and of our
own students of color.
Regular Peer Support
- Pals of PALS, pals@grinnell.edu, normally Saturday at 7:45 am (breakfast
included; felines only), and Mondays at 4:45. Requires sign up in
advance. MORE HELP NEEDED!
- Socrates Cafe', Saturdays, Younker, 2pm.
- Pun Club, Saturdays, 4pm, Way over Younker.
Upcoming Peer Support
- Women's Basketball vs. Beloit, Nov. 28 at 3:00 p.m.
- Women's Basketball vs. St. Norbert, Dec. 5 at 3:00 p.m.
- One-act Festival Dec. 5 & 6.
- Women's Basketball vs. Carroll, Dec. 12 at 3:00 p.m.
Other Good Things (No Extra Credit)
- Jazz Band Wednesday.
- Latin-American Ensemble Thursday.
- Swim Meet Saturday.
- Jingle Bell Holiday Friday.
Background: Guiding Principles
- Write less, not more
- It (usually) makes you faster.
- It (usually) makes your code more readable.
- It (usually) makes your code easier to maintain.
- Refactor
- Don't write repetitious code
- If you are programming by copy-paste-change, you're probably wasting
time.
- Name appropriately
- Good names for things that need names
- No names for things that don't need names
Background: The Value of Repetition
The following is variant of something my colleague John Stone says ...
You learn from reading.
- The first time you read a new procedure structure
(such as recursion over a list), you learn something.
- The second time you read the same structure, you learn something else.
- The third time, you learn a bit more.
- After that, reading doesn't give much benefit.
You learn from writing.
- The first time you write the same structure, you learn something more
about that structure
- The second time, you learn even more.
- The third time, you learn a bit more.
- After that, there's almost no benefit.
So ... extract the common code so you don't have to write it again.
Procedures as First-Class Values
- We'll look at one way to achieve our guiding principles and write
common code.
- The big picture ideas:
- You can write procedures (like
map) that take other procedures
as parameters.
- You can write procedures (like
left-section and compose) that
return other procedures.
- Doing so makes your code better.
- Procedures are, in effect, yet another kind of value. What are the
questions we normally ask about new types of values?
- Taking a procedure as a parameter is easy. You just include it as a normal
parameter and use it as a normal procedure.
(define apply-to-2-and-3
(lambda (proc)
(proc 2 3)))
- Returning procedures is a bit harder. You usually just return an anonymous
procedure. That means you'll have multiple lambdas.
(define adder
(lambda (n)
(lambda (x)
(+ x n))))
(define inc (adder 1))
Old Notes
The following are notes I wrote for past versions of the course. I probably
won't discuss any/all in class.
Two Motivating Examples
all-real? and all-integer?
add-5-to-each and multiply-each-by-5
Procedures as Parameters
- We've been writing it a lot.
- Useful
- Concise
- Supports refactoring
Procedures as Return Values
- Another way to create procedures (anonymous and named).
- Strategy: Write procedures that return new procedures.
- These procedures can take plain values as parameters:
(define redder
(lambda (amt)
(lambda (color)
(rgb ...))))
- How to think about this:
- a procedure that takes amt as a parameter,
- returns a new procedure that takes color as a parameter
- Can also take procedures as parameters
- One favorite:
compose
<>boxcode
(define compose
(lambda (f g)
(lambda (x)
(f (g x)))))
- Examples
- sine of square root of x:
(compose sin sqrt)
- last element of a list:
(compose car reverse)
- Another:
left-section
(define left-section
(lambda (func left)
(lambda (right)
(func left right))))
(define l-s left-section)
- Examples:
- add two:
(l-s + 2)
- double:
(l-s * 2)
- Not mentioned int he reading, but there's a corresponding right-section
(define right-section
(lambda (func right)
(lambda (left)
(func left right))))
(define r-s right-section)
Encapsulating Control
- Possible for complex common code, too (particularly control).
map is the standard example.
(define map
(lamda (fun lst)
(if (null? lst)
null
(cons (fun (car lst))
(map fun (cdr lst))))))
- Another issue: Checking the type of elements in a list
(define all-numbers?
(lambda (lst)
(or (null? lst)
(and (pair? lst)
(number? (car lst))
(all-numbers? (cdr lst))))))
(define all-symbols?
(lambda (lst)
(or (null? lst)
(and (pair? lst)
(symbol? (car lst))
(all-symbols? (cdr lst))))))
(define all
(lambda (test? lst)
(or (null? lst)
(and (pair? lst)
(test? (car lst))
(all test? (cdr lst))))))
Concluding Comments
- Yes, skilled Scheme programmers write this way.
- It's quick.
- It's clear (at least to skilled Schemers).
- It reduces mistakes.
- The ability to encapsulate control in this way is fairly unique to Scheme
(well, to functional languages).
- It's one of the reasons we love it at Grinnell.
- Or at least a reason I love it.