Consider the following two programs from the exam:

(define (get-character-names aloc)
  (cond [(empty? aloc) empty]
	[else (cons (character-name (first aloc))
		    (get-character-names (rest aloc)))]))

(define (all-lose-life aloc)
  (cond [(empty? aloc) empty]
	[else (cons (make-character
		     (character-name (first aloc))
		     (- 1 (character-lives (first aloc)))
		     (character-moves (first aloc)))
		    (all-lose=life (rest aloc)))]))

Can you write a function that abstracts over these two programs?  We
proceed as before, locating the spots where the programs differ and
adding parameters to account for these spots:

(define (process-characters ... aloc)
  (cond [(empty? aloc) empty]
	[else (cons ... (first aloc)
		    (process-characters (rest aloc)))]))

Using process-one to fill in the ... in the cons yields the following

(define (process-characters process-one aloc)
  (cond [(empty? aloc) empty]
	[else (cons (process-one (first aloc))
		    (process-characters process-one (rest aloc)))]))

Process-characters takes a list of characters and a function that
consumes characters.  It produces a new list where we've applied the
function to each character in the input list.  For example, we could
write get-character-names using process-characters as follows:

(define (get-character-names aloc)
  (process-characters character-name aloc))

What should we write as the contract for process-characters?  Let's
look first at the outputs.  When we write get-character-names, we
produce a list-of-symbols.  When we write all-lose-life, we produce a
list-of-characters.  How do we write the data definition for the
output list?

One option is to create data definitions for char-or-sym and
list-of-char-or-sym.  What's wrong with this option?  First,
list-of-char-or-sym allows symbols and characters in the same list.
Our examples use lists of only one type of data.  Second, this
restricts keep to processing only lists containing symbols or
characters.  What if we wanted to use process-characters to produce a
list of numbers?  We don't want to have to change the contract every
time we find a new use for process-characters.

Let's look at the two data definitions for lists of symbols and list
of characters:

A list-of-symbols is either
  - empty, or
  - (cons S los) where S is a symbol and
                       los is a list-of-symbols

A list-of-characters is either
  - empty, or
  - (cons C loc) where C is a character and
                       loc is a list-of-characters

Where do these definitions differ?  Only in the type of the first
argument to cons.  We can share the common structure of these data
definitions by writing a new data definition that uses a variable for
the type of the argument.

A list-of-alpha is either
  - empty, or
  - (cons A loa), where A is an alpha and
                        loa is a list-of-alpha

We'll use the abbreviation (listof alpha) for a list containing
elements of type alpha.  Thus list-of-symbol is (listof symbol) and
list-of-characters is (listof character).  We will use names of greek
letters to denote variables over a type.  Thus. (listof alpha) means
we have a list of elements of type alpha, but that we don't know
what alpha is.

Now, we can write a contract for process-characters.

;; process-characters :
;;        (character -> alpha) (listof character) -> (listof alpha)

Consider the program double-all, which takes a list of numbers and
returns a list of numbers where each number in the input list has been 

(define (double-all alon)
  (cond [(empty? alon) empty]
        [else (cons (* 2 (first alon))
                    (double-all (rest alon)))]))

How does double-all compare to process-characters?

;; process-characters :
;;        (character -> alpha) (listof character) -> (listof alpha)
;; applies the argument function to each character in the input list
(define (process-characters process-one aloc)
  (cond [(empty? aloc) empty]
	[else (cons (process-one (first aloc))
		    (process-characters process-one (rest aloc)))]))

Both programs are quite similar: they consume a list and produce a new 
list formed by applying an operation to each element in the input
list.  Can we write an abstract version of these two functions?  Yes.
Let's call it map.

;; map : (beta -> alpha) (listof beta) -> (listof alpha)
;; applies the input function to every element of the input list
(define (map f l)
  (cond [(empty? l) empty]
	[else (cons (f (first l))
		    (map f (rest l)))]))

Mapping in such a common operation in programming, that map is
actually built-in to DrScheme.  Here is double-all written in terms of 

(define (double-all alon)
  (local ((define (double n)
            (* 2 n)))
    (map double alon)))

Now, consider again our keep program from Monday:

;; keep : (num -> boolean) lon -> lon
;; keeps all numbers for which keep-elt? returns true
(define (keep keep-elt? alon)
  (local [(define (filter a-lon)
	    (cond [(empty? a-lon) empty]
		  [(cons? a-lon)
		   (cond [(keep-elt? (first a-lon))
			  (cons (first a-lon) (filter (rest a-lon)))]
			 [else (filter (rest a-lon))])]))]
     (filter alon)))

Now consider the program remove-dead from the first exam.

;; remove-dead : loc -> loc
;; removes all characters with less than one life from the list
(define (remove-dead aloc)
  (cond [(empty? aloc) empty]
	 (cond [(>= (character-lives (first aloc)) 1)
		(cons (first aloc) (remove-dead (rest aloc)))]
	       [else (remove-dead (rest aloc))])]))

Can we write an abstract program that covers both keep and
remove-dead?  Keep is actually close.  In fact, we could write
remove-dead by doing the following:

(define (remove-dead aloc)
  (local ((define (keep-character? a-c)
	    (>= (character-lives a-c) 1)))
    (keep keep-character? aloc)))

There's one problem with this however.  The contract for keep requires
a function from num to bool as the first argument.  We are passing a
function from character to bool.  Clearly, we should be able to use
keep to write remove-dead.  How do we write the contract for keep to
allow both uses?

;; keep : (alpha -> boolean) (listof alpha) -> (listof alpha)

Keep is such a useful function that it is actually built-in in
DrScheme.  It is called filter.

Look again at the new definition of double-all.  When we first
discussed local, we said that we wanted to use it in two cases: to
avoid computing values more than once, and to make complicated
expressions more readable.  In the final definition of double-all, the
local function double appears only once and is quite simple; thus, it
doesn't really require its own name.  Can we write double-all without
using local?

In order to do this, we need some way to write programs without giving
them names.  So far, we only know how to write programs using define.
Scheme provides a keyword with which one can write un-named programs.
That keyword is called lambda.  Here's an example of how we could
write double without naming it:

      Named                          Unnamed

(define (double n)                 (lambda (n)
  (* 2 n))                           (* 2 n))

Using the unnamed version, we could rewrite double-all as follows:

(define (double-all alon)
  (map (lambda (n) (* 2 n))

Lambda is very useful because it lets us refrain from introducing
unnecessary names in programs.  You can think of lambda as a shorthand
for (local ((define ...) ...) that is useful if you use the locally
defined program only once.