Let's take a look at the natural numbers defined inductively.

N ::= 0 | succ N (define even? (lambda (n) (cond ((zero? n) #t) (else (odd? (- n 1)))))) (define odd ...)Repeated patterns in programming are bad because each repetition offers another opportunity to introduce a bug. Use procedures to abstract common patterns. Consider the problem of adding one to each element of a list.

(define add-each (lambda (l) (cond ((null? l) '()) (else (cons (add1 (car l)) (add-each (cdr l)))))))Suppose we also need to subtract one from every element.

(define sub-each (lambda (l) (cond ((null? l) '()) (else (cons (sub1 (car l)) (add-each (cdr l)))))))These procedures are nearly the same. We can write one procedure, abstracting over the operation:

(define each (lambda (f l) (cond ((null? l) '()) (else (cons (f (car l)) (each (cdl l)))))))This procedure is map.

Now consider multiplying all the numbers of a list together.

(define *-overlist (lambda (l) (if (null? l) 1 (* (car l) (*-overlist (cdr l))))))If we also wanted to define

`+-overlist`

we should use procedure
abstraction. To do this we write a folding function. Folding can occur
either to the left or to the right. The procedure above folds to the
right.
(define foldr (lambda (f i l) (if (null? l) i (f (car l) (foldr f i (cdr l)))))) (define *-overlist (lambda (l) (foldr * 1 l)))

`foldr`

multiplies elements from right to left. We can also build
a fold function that works left to right.
(define foldl (lambda (f i l) (if (null? l) i (foldl f (f i (car l)) (cdr l)))))The direction of the fold does not matter in the case of a communicative operation. But if the function is not communicative or has side effects the direction of the fold is quite important. Note how we can now define

`map`

using `foldr`

.
(map f l) = (foldr (lambda (a b) (cons (f a) b)) '() l)Much of this we can also do in C, but suppose we can define a function that adds n to its parameter in the following manner.

(define add-n (lambda (n) (lambda (m) (+ m n)))) (map (add-n 3) '(1 2 3))This example shows that we can construct open procedures that capture the value of bound variables. You can not do this in C, hence procedures like

`map`

and `fold`

are less useful in C.
Convince yourself that the following are equivalent.

(lambda (x y) (let ((x y) (y x)) x))) (lambda (x y) ((lambda (x y) x) y x))This example shows that

`let`

is a syntactic abstraction. In general
(let ((x[1] e[1]) ... (x[n] e[n])) e') = ((lambda(x[1] .. x[n]) e') e[1] ... e[n])The reason that

`let`

is not a function is that it manipulates
bindings. Why else might we want to have syntactic abstractions? Consider
the following.
(cond ((test then[1] ... then[n]) clause*)) = (if test (begin then[1] ... then[n]) (cond clause*))) (cond (else e[1] ... e[n])) = (begin e[1] ... e[n]) (cond) = undefHere we see the second motivation for syntactic abstraction: to change argument evaluation order. Now lets look at

`and`

and `or`

.
(and e[0]) = e[0] (and e[0] ... e[n]) = (if (e[0]) (and (e[1] ... e[n]) #f)) (or e[0]) = e[0] (or e[0] ... e[n]) = (let ((x e[0])) (if x x (or e[1] ... e[n]))) x not in FV(e[1] ... e[n])Scheme has short-circuit evaluation like C. Suppose that we forget the condition that x not be in FV(e[1] ... e[n]).

(define x 1) (or #f x)This should be 1, but instead it is expanded into

(let ((x #f)) (if x x x))What happened? variable

`x`

was captured by the binding introduced
by the macro. We must have the hygiene condition that x not in
FV(e[1] ... e[n]) to prevent this. We usually
want hygiene for all variable bindings introduced by a macro. Hygienic macro
systems do this automatically. The following shows that we have the
same problem in C.
#define swap(x,y) { int temp = x; x = y; y = temp; } ... swap(temp,x);

You can define macros in our Scheme system using
`extend-syntax`

. There you will find
some examples of how to use this feature. Although the extend-syntax system
we are using is not hygienic, we can get a little bit
of help from `gensym`

. It generates a unique symbol within
the context of an `extend-syntax`

expression. The following
is an outline for the definition of `or`

.

(extend-syntax (or) ((or e) e) ((or e1 e2 ... ) (with ((x (gensym))) (let ((x e1) (if ... ))))))

- Derive map from foldl.
- Define cond, or, and using extend-syntax.

- Seasoned Schemer Chap 14-18.
- EOPL Chap 3,5