Documente Academic
Documente Profesional
Documente Cultură
the
Art
^of Programming
'^d
2012
http://archive.org/details/schemeartofproOOincs
/'
Scheme
and
The Art
of
Programming
George Springer
Daniel P. Friedman
Foreword by
Guy
L. Steele Jr.
Scheme
and
The Art
The MIT
of
Programming
Press
New York
St.
Second
Printing,
1990
of Technology
by any
Institute
electronic or mechanical
means
This book was printed and botmd in the United States of America
Library of Congress Cataloging-in-Publication Data
Springer, George, 1924-
Scheme and
Friedman.
p.
cm.
(The
P.
and computer
science series)
Programming.
programming.
QA76.6.S686
005.1dc20
I.
Friedman, Daniel P. E.
Title.
2. Object-oriented
HI. Series.
1990
89-12949
CIP
Contents
Foreword
Preface
xiii
xix
Acknowledgments
Part
xxiii
Data
Chapter
1.1
Introduction
1.2
The Computer
1.3
Taking
Chapter
2.1
Lists
Apart
14
19
Overview
2.2 Procedures
31
31
2.4 Recursion
2.5 Tracing
40
^5
and Debugging
57
31
Chapter 3
3.1
Overview
13
3.2 Operations
on Numbers
Overview
101
5.3
Numbers
Overview
6.2 Strings
Part 2
166
Contents
118
193
Abstracting Procedures
195
7.2 Procedures as
viii
168
Overview
163
163
Procedures as Values
7.1
Programming
163
and Output
Chapter 7
H2
155
Interactive
6.4 Input
129
129
Chapter 6
6.5
120
129
and Letrec
5.4 Binary
6.1
Algorithm
115
Overview
5.2 Let
108
and Iteration
5.1
95
95
Deep Recursion
Chapter
SJt
95
4.3
Chapter 4
4.1
13
195
195
13
7.3 Currying
210
Chapter 8
8.1
Part 3
236
249
Managing State
Chapter 9
9.1
Overview
9.2 Vectors
9.4 Matrices
Chapter 10
Overview
10.2 Sorting
10.3 Searching
Using Vectors
267
267
267
278
290
303
329
332
Mutation
11.1
Overview
11.2
341
341
34
Chapter 12
Contents
303
303
Chapter 11
255
265
10.1
231
231
223
231
8.2 Quantifiers
8.3 Sets
Deep Recursion
Overview
218
Cons
Cells
360
Object-Oriented Programming
383
ix
12.1
Overview
383
Queues
399
403
12.6 Buckets
Chapter 13
Part 4
409
13.1
Overview
13.2
Randomness
13.3
The Gas
4^^
Station Simulation
Overview
Macros
4^0
15.3 Streams
475
^75
475
482
Data
^P5
500
15.5 Files
513
Chapter 16
Contents
Form
Using Streams
Overview
Control
449
454
Chapter 15
15.1
^^7
44^
Part 5
4^0
Chapter 14
14.3
425
425
14.1
383
396
12.3 Stacks
12.4
and Gauges
Introduction to Continuations
515
16.1
Overview
515
16.2 Contexts
516
16.4 Continuations
523
530
538
541
16.8 Escaping
16.9 Escaping
Chapter 17
544
546
Using Continuations
17.1
Overview
551
17.2
Review of
call/cc
17.3
551
551
553
17.8 Final
Appendices
Thoughts
567
57i
575
A 1.1 The
Index
Problem
559
579
Al
References
557
17.7 Grune's
527
ASCII Table
Set
579
A 1.2
A1.3
How
to
579
580
580
581
583
Contents
xt
Foreword
I'm not going to spend much space talking about how great
me
the manuscript.
you what
Small
is
beautiful.
Small
is
powerful.
is
easy to understand.
large
How
the
small
or
like
is,
in
Small
book
this
is
small.
It
packs a
is it?
the business of
Common
Curious,
is it
COBOL
810
ATLAS
790
Fortran 77
430
PL/I
420
BASIC
360
ADA
340
Fortran 8x
300
220
Pascal
120
DIBOL
'90
Scheme
~50
it
from
me
1000 or more
Lisp
or
perhaps
the primary measure of a language's merit, whether one thinks that larger
is
better.
for
my
children,
and
drill bits.
Each has a
specific purpose,
and for precision work most cannot be replaced by any combination of the
others.
in
if I
break a bit
size.)
In
can usually
some
cases the
business ends of several tools are the same, but they have different handles.
I
have a
set of screwdrivers
less likely to
xtv
Foreword
and,
when a
particular task
COBOL,
or
or Fortran
But
is like.
it
army
screwdriver, a
It
"Craftsman" model.
It is
flat
file,
an awl, bottle opener, can opener, tweezers, and of course the traditional
plastic toothpick. It weighs five ounces (142
Now,
knife.
But
virtually
let
is
you,
tell
unburdened and
to reach into
saw
me
my
is
it
yet,
my
back
gm).
stairs using only a Swiss
repair task
accommodate Ethernet
cables.)
disposal.
have used
And my
army
feeling
life
comes to hand,
my
office furniture to
my
it
to
(The
modify
is
my
six- year-old.
in
had one
at
1975,
defined
lambda
calculus,
it
knife.
in all of
computer science
abstraction.
is
(However,
it
clearly recall
my
father telling
me
that
most of
life is
detail.
unadulterated extreme.
of startling generality.
It
The lambda
if it
were simpler,
complex quantity
The operations
are:
Synthesis:
Foreword
content.
parallel.)
its
throwing away
possible.
cannot
of carefully throwing
data, you reduce
it
Com-
We make complex-
close
all.
or rather,
Hewing
xv
Naming
is
language, for
in
any
it
primitive atom.
The
inverse of abstraction
is
up of complexity from
programming languages provide dozens or
Industrial-strength
lesser pieces.
What
macho
to provide a single
is
(or
maybe
macha.
if
means
of
pieces: two.
You
lambda
cein
calculus there
is
may
is
to talk about:
it
is
lies
the
the objects to be
all
in the
be combined. Here
Abstraction
itself!
is
That's
it
as powerful as
it.
lambda
once, the
calculus
is
is
a bit spare.
One can
Hemingway,
or
write the
Ann Landers
using only a few dozen letters and punctuation marks, but only a few of
us
all
day discussing
rest of society
and
wish to
sit
rules of punctuation.
around
More
to
the pomt, these great works are not best understood at the level of spelling
and punctuation.
We
dictionaries.
treat
From words we
and
fairy tales
everyday discourse.
The
original
Scheme consisted
of
little
more than
the
lambda
calculus, a
means
rvi
the
Foreword
my
efforts to
Common
little
Lisp,
to
do with the
though cheering
am
in little
danger of straining
my
efforts.
less
large one, filled with a careful selection of tools that will cover
most jobs
and a few
It's
tools
is "real,"
Scheme
can grasp
to
is
easily
It is
make
it
easy to
it
than a
full
a toolbox, a
make more
well,
tools.
in
it
is
it all
It is
it
on which there
in
is little
agreement and
in
which
it
may be
usefully contrasted
with C, Fortran, or Pascal. Nearly everyone agrees that "+" should stand for
addition.
Scheme focuses
erality to
list.
my
hoo, boy!
tags, block
may be named, by
first class.
are there
many namespaces
(variables, functions,
go
)?
.
.
In Pascal,
why
can't
dure?
In Fortran 77,
In C,
why
why
its
own
right,
complete design with which to compare other languages and thus shed light
on these questions.
Guy
L. Steele Jr.
Cambridge, Massachusetts
July 1989
Foreword
xvii
Preface
in their expression,
general in their application, and easily understood. These goals are achieved
We
to be simply used.
programming language Scheme is superior for use in an introductory programming course because it is both simple and powerful. It
is simple enough that program design can be learned with a minimum of
distraction by syntactic rules that govern the form programs must take. In
a typical introductory course the complex syntax of programming languages
such as C or Pascal must be mastered at the same time that elementary program design techniques are being learned. Invariably syntactic concerns take
believe the
if
a program. As a
ming
will
impression of programming
may
persist, or
it
may
first
will
be easier to master.
In-
than
its
mathematics.
In
many
We
feel it is
for
which
it
is
char-
closer in spirit to
lems
is
comprehensible programs.
functional
and
It is
as recursion
may
Traditional
well suited.
niques.
when
it is
is
appropriate.
recent advance in
object-oriented style
simulating objects in the "real world" and for structuring large systems in
ways that allow recurrent patterns of computation to be shared by similar objects. Using Scheme, we are able to illustrate the principles of object-oriented
programming
This book
in
is
composed of
five parts.
gramming techniques
are developed.
is
first
so
The
to control
Preface
The
third
We
iterative pro-
pression.
and
we take advantage
first
we demonstrate
of
a unique
program execution
in
we
difficult or
make
it
possible
impossible in other
languages.
The
come
in
two
As
one-fifth
varieties.
making up
in
have also included optional exercises that present extensions of the material
in the text.
first
in
on the
in order,
is
required but a
full
in
Chapter 5
is
not
The
necessary.
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<
^
^
^
^
^
^
^
^
^
^
^
^
^
^
^
J'
'
j<
J'
J'
'
11
J'
11
12
J'
11
'
14
J'
11
J'
11
16
is its
We
From
without Chapter 6
is
it
in
essential.
Preface
class-
first
One sequence
many
xxt
and
15.
to skip
is
ing the
first
in
and
and
6,
15,
and the
last section
2) in the first
manner
first five
You
are about to
Programming,
embark on a most
especially in Scheme,
is
7, 12,
and 14-17.
exciting
fun!
Tigger on Scheme
is:
Its clear
RUN!
But
Random
House,
New
York, 1975,
ixtt
Preface
is:
Acknowledgments
Many
want
to
tent,
and
exercises.
when we needed
manuscript in
We
gestions.
We
advice.
its
Our thanks
also go to the
who
served as consultants
many
people
who
read the
those teachers
We
and
correctness.
who worked
Our appreciation
is
likewise extended to
who taught from our manuscript and to their students who gave
The input from each class testing improved the book
us helpful criticisms.
those
who
it.
We
also
offered us encouragement.
So we thank
Hal Abelson, David Hartley, Andrea Berger, Bhaskar Bose, Jose Blakeley,
Tom
dinger, Olivier Danvy, Bruce Duba, Kent Dybvig, Sue Dybvig, Matthias
Felleisen,
Mary Friedman,
Harlan,
Hieb,
feel
for the
this
book.
We
also
We
want
to
for
support of research
to those in the
thanks go to
PC
Scheme.
We
in developing
macros provided by
Amy
Hendrickson.
finally
MIT
Book Co.
xxiv
We
Acknowledgments
grati-
was a
Part
Data
Data are
we are introduced to a recursive characwe study the way Scheme treats symbolic,
Chapter
1,
we build procedures
for processing
We
We
symbolic data.
can
bill,
and
We
exit.
do
not think about the procedure for a particular restaurant, but we abstract
over
all
restaurants.
is
to present
Recursion
for
is
will
be general.
1.
data described recursively, but also the procedures, which process the data,
are recursive.
In Chapter
3,
We
We
intro-
conclude
Much
theme of this book is the understanding of programming with abstract types and this is the first such example.
data type.
In Chapter
4,
of the
and
it-
eration. Here we combine the various data types into different structures and
We
5.
Chapter
6,
we show some
Data
Beauty
.it is
is
it is
If
we
making
it.
doing.
of
Computing is an art form. Some programs are elegant, som,e are exquisite,
some are sparkling. My claim, is that it is possible to write grand programs,
noble programs, truly magnificent program,s.
Donald
from an
article
Knuth,
by William Marling
in
1.1
E.
Case Alumnus
Introduction
Computer programming is many faceted.
It is engineering.
Computer programs must be
carefully designed.
They
They
is
craft.
is
highly
plastic,
than
unconstrained by physical
In
reality.
more. Simplicity
is
complexity.
it
may
for
is
When
in
We
be a thing of beauty.
is
is
it
based on one:
computer
is
style of this
Though
programming, we
science.
scientific results.
book to be
We
is
Of
a literary endeavor.
course,
not enough!
But that
Thus
needs.
intelligible
by humans as well as
is
tions
programs be
essential that
it is
This
style
habits we attempt to
instill
by example
in
this book.
But
and
this
book
literate
is
programs.
specified step)
in turn
(step by well-
encourages an
is
pro-
and
almost every
field
writing ability,
is
Programming
An
of study.
Thus programming
ability, like
in
mathematical and
and
literary ability
in
common.
essay or short story can be correct grammatically and can convey the
its
own
still
aesthetic,
in their readers.
art.
strive to
Writing
metaphors
it
command
of the
can support.
There are many languages from which to choose when designing a course
to teach the principles of programming. Scheme was selected because it is
an expressive language that provides powerful abstraction mechanisms for expressing the solutions to computational problems. This facilitates the writing
of clear and satisfying programs.
It is
especially
good as a vehicle
for teaching
first
fourth revision
is
expected
an IEEE Standard
for
for
The
The
in 1989.
There
Scheme.
A number
is
of books about
Scheme have
Computer Programs by Abelson and Sussman with Sussman, MIT Press and McGraw-Hill Book Company, 1985.
The
Little
Felleisen,
MIT
Press, 1987
and
SRA
Pergamon, 1989.
Programming
An
The
Scheme by Eisenberg,
in
Introduction to
Scheme by Smith,
Prentice-Hall, 1988.
PC Scheme,
We
by Texas Instruments,
philosophy.
We
ferent stories to
As you read
programs
are.
are
all
its
own programming
somewhat
dif-
tell.
these pages,
The
is
care
how
elegant your
this as
1.2 The
Computer
1.2
The Computer
We
it
1.
The
input deuce, in this case the keyboard with the standard typewriter
On
several functions.
(CTRL)
On
the computer,
we
the Alternate (ALT) key while pressing another key to get yet another
behavior.
Finally, pressing
the result
2.
The
is
usually
still
another behavior.
shown on the
a key
is
pressed,
screen.
memory
When
is
of the computer, the arithmetic logic unit, and the registers where
The output
is
viewed, which we refer to as the screen, and the printer where printed
The
is
produced.
reads
files
The
and
all
larger
file
on a
diskette.
Many microcomputers
files
can be stored
and accessed.
Implementations of Scheme are available on a wide variety of computers
ranging from larger mainframe computers that support
many
users to indi-
1.3
make
computer do something
for us.
sentences.
characters written one after the other with no blank spaces between them.
is,
The computer languages also have their analogs of words, which we call symbols. The characters used to make up the symbols are the same characters on
We
through
special
meaning
in English. In
+ -
character.
The
following
list
are used in
like
()[]{};."''#
have special meaning and cannot appear
and some
9,
comma have
shall
in
first
Numbers
would expect,
10, -753,
form a separate
word.
We
and when we
we
retrieve its
Scheme
symbol,
it
checks to see
if it is
Otherwise
tells
it
is
meaning
given a
If so, it
can
given a meaning.
To
carry the analogy with the English language a step further, words are
put together in sentences to express the thoughts you want to convey. The
which
is
defined to consist of a
left
1.3
We
first
and return to
When
message
telling
[1]
If
(sometimes referred to as
[1]
Scheme
number
after the
press the
<RETURN> key
<RETURN>
We
is
the
number 7
or that what you type has been evaluated to give the number 7. Scheme then
writes the value of what you type at the beginning of the next line and moves
down one more line and prints the next prompt:
[1]
7.
is
the
<RETURN>
[2]
first
is
called
it
to the
you enter
in response to the
it
reads,
it
evaluates,
Scheme waits
for
and
its
it
We
three
refer to this
read-eval-print loop.
After
example, when you press <RETURN>, Scheme completes one cycle of the loop
a symbol
is
first
that
you type the symbol ten and press <RETURN>. If Scheme has not previously
been given a meaning for the symbol ten, we say that ten has not been bound
to a value. In the evaluate phase of the read-eval-print loop, no value
is
found
for ten,
and a message
is
and
ten <RETURN>
[2]
we want
How
form of expression
this case
is
is
this
purpose we use
identified
is
in
as follows:
[3]
In this example,
expression
is
the language.
Now
let's see
ten <RETURN>
[4]
10
it
prints the
value 10.
We
When
is
(i.e.,
a value)
a value
given to a variable,
is
The
define expression
is
made up
of a keyword, a variable
name
var,
and an
expression expr.
Now
let's
is
bound
to 10
1.3
Scheme not to evaluate ten but to print its literal value ten. The
mechanism that Scheme provides for doing this is called quoting the symbol.
We quote a symbol by enclosing in parentheses the word quote followed by
of telling
the symbol:
(quote symbol)
For example, you quote the symbol ten by writing (quote ten).
in response to a
If
you type
see
[5]
ten
From now
on,
we
shall
It
is
understood that
We
in response to the
to
what we
In
all cases,
quoted symbol
it
Scheme evaluates
Scheme evaluates
"If
is
[6]
bound
to ten, while
if
enter
is
"returned."
to 10,
and you
to 10."
whether a symbol
is
it
is
is
number
as an expression
the
number
itself.
(quote abc3)
abc3
[7]
(quote 12)
12
An
this
It
is
the
is
also available
Scheme.
10
also be
made
as follows:
'abc3
[6]
abc3
'12
[7]
12
We
For example,
if
we enter the
is
following:^
[8]
we bind the
we get
variable
When we
Robert
[9]
Bob
so that
how we do
a brief look at
for a
at using
numbers
in
Chapter
3.
To perform
the
numbers
operates on.
The numbers on
operator
is
which
it
placed to the
operator and
its
left
of the
[10]
7.
On
in
it
(+3
it
it
and
(+ 3 4)
We
'
evaluates
it
to bob.
letters, so that if
1.3
we enter
'Bob,
Scheme evaluates
it
all
uppercase
to BOB.
11
Multiplication
is
How
division with /.
*,
subtraction with
and
5)?
,
x (12
In prefix notation,
first
number
12 and
5,
expression
[11]
3.
is
entered as
(* 3
(-
(+ 2
(/ 30 15))
12 5))
21
[12]
In general,
Scheme
of operator to
operands.
its
We
it
shall return to a
3.
numerical operations are included in the exercises at the end of this section.
is
particular
mechanism
If
for doing so
file.
In
The
Scheme
may
some implementations,
it is
file.
Some
in the
window
Scheme in an editor
preserve what you want from
possible to run
is
to
it
the
keyboard.
12
Exercises
Exercise 1.1
Scheme
session in a
session in a
file
for recording
your
file.
'
what
see
is
returned.)
Exercise 1.2
Assume
(define
(define
(define
(define
(define
What
made
big-number 10500900)
small-number 0.00000025)
Cheshire 'cat)
number 1 big-number)
number2 'big-number)
when
prompt?
a.
big-number
b.
small-number
c.
'big-niunber
d.
Cheshire
e.
'Cheshire
f.
number 1
g.
number
h.
'
number
in order to verify
your answers.
Exercise 1.3
What
the
is
the computer.
a.
(- 10 (- 8 (- 6 4)))
b.
(/ 40 (* 5 20))
c.
(/ 2 3)
d.
(+ (* 0.1 20)
(/ 4 -3))
Exercise I.4
Write the Scheme expressions that denote the same calculation as the following
arithmetic expressions.
1.3
13
-(13 +
a.
(4x
b.
(3x(4 + (-5--3)))
c.
(2.5^(5 X (1^10)))
7)
5)
X ((537 X (98.3
d. 5
(375
(2.5 x 153))))
255)
Exercise 1.5
If a,
/?,
and 7 are any three numbers, translate each of the following Scheme
a (+
(+
(+
(+ (*
/?)
(* 7 /?))
(/ (-
/?)
(-
(+
b.
c.
7))
translates into
+ (,3 +
7)
7) a))
(-
a.
/9
/?
Q 7))
we have seen two data types, symbols and numbers. Another important
data type in Scheme is lists. We all use lists in our daily lives shopping lists,
So
far,
laundry
is
address
lists,
lists,
simple operations on
lists.
how
In Scheme, a
forth. In
it
to build lists
list is
computing,
and how
to perform
is
list
is
constructor of
lists.
We now
look at
how cons
want to build a
[1]
(cons
list
its
works.
We refer to cons as a
We shall first perform
we
number
1.
We
'())
(1)
We
see
from
this
1.^
number
1,
list
'().
in parentheses:
The
first
entry
the
tells
us
name
the
tell
of the procedure
The
argument
argument
Scheme
is
is
list
the
we
list
we
enter.
are constructing,
reads what
first
item in the
first
values of
we
list
are building.
list is built.
It
list
We
is
placed to the
left
of the operands, using prefix notation.) Let us bind the variable Isl to
the
list
number
containing the
[2]
[3]
Isl
by writing
'()))
(1)
The define
expression
we entered
at the
prompt
variable Isl
is
list
(1).
entered at the
'()).
to the
its
list
That
(1).
value (1)
is
returned.
We now
the rest of
[4]
create a
list
elements.
its
with 2 as
its first
To accomplish
this
we
write
(cons 2 Isl)
(2 1)
[5]
Isl
(1)
Once
to the
again, the
list
Then a new
prompt
[5],
its
we
list like
list is
formed having 2 as
items, giving us (2 1)
verify that
Isl
is
its first
This
is
is
[6]
[7]
l82
(2 1)
[8]
Isl
(1)
t.4
Constructing Lists
15
The
expression entered at the prompt [9] binds the variable c to the literal
We
[9]
When we
first
containing three as
rest of its
its
elements by writing
'three)
1)
apply cons to
operand,
ates to the
list
c,
is
its
Then a new
(2 1).
2 1)
list
(cons c ls2)
[10]
(three 2
The
list is
(2 1) as the rest of
list
three
built with
its
elements.
and
returned.
Continuing our experiment, we bind the variable ls3 to the value of (cons
c ls2) using a define expression:
[11]
We now
has as
ls2))
its first
item the
This
as those in ls3.
list
is
ls2 and
Let us build a
list
that
same items
operand and ls3 the
first
[12]
((2
[13]
three
The
1)
ls3
(three 2
[14]
1)
first
that has as
its first
item the
list
(2 1),
list
This gives us the value that was returned by Scheme: ((2 1) three 2
Notice that when ls3 was entered in response to the prompt [13]
1), the original value of ls3,
We
list
1).
(three 2
list
and
ls3.
16
are
operands,
all
is
called
an application, and
is
evaluated by Scheme,
all
The
unspecified order.
applied to
value of the
is
We
new
followed by
It is this
all
new
may
that
list
evaluates
is
be numbers, the
have assumed
of this book,
that a
list
may
we
may
itself
list.
contain in
This
other
it
The
list.
nesting
contain nested
lists.
Thus,
list.
Then a
list).
operand as
its first
item
if
list
these values
far,
of these items.
lists
As
is
argument
lists.
may
We
to
we
shall en-
cons not to be a
we
see in
list is
ls4
nested
We
now
lists.
it is
We shall
first
literal
application evaluates to a
counter, but
for
be the empty
list.
assume
may
list
lists
We
operands, the
its
is
some
is
list is
first
(which
list
are evaluated in
list
to be
to be constructed).
list is
an application
first
When
operands.
its
the given
list is
list
Items that
list.
e,
the
list
(1 g),
h.
list
[15]
(cons 2 (cons
'()))
(2 1)
To
construct the
[16]
list
'()))
'()))))
((2 1) three 2 1)
list
(three 2
1).
Then
list
the
fifth,
and
list.
17
We
define, and
in a list of values.
in parentheses,
it
When Scheme
first
is
left
parenthesis
item
It
tells it to do.
Scheme prompt?
[17]
(2
1)
first
item
list
it
in the list is
its first
it
tried to treat
it
2,
which
not a procedure.
Is
some way
there
answer
is
yes.
three.
2.
1.
the
parentheses
list
of items that
We
is
list
is
to be taken literally?
it
in front of
to be taken with
its literal
we would
The
parenthesis.
left
to enter a
value.
Thus
enter '(three 2
to get a
1).
list
in the
containing
should not be quoted within the parentheses since the outer quote already
indicates that
it
its literal
value.
Let's look at
some
more examples:
[18]
'((2 1) three 2 1)
((2 1) three 2 1)
[19]
'(a b (c (d e)))
(a b (c (d e)))
[20]
(cons '(a b)
'
(c
(d e)))
((a b) c (d e))
We now
list
we enter
We
is
consists of literal
more
18
fvilly
in
is
not a quoted
list,
and the
item
first
in the list
We
/,
is
is
to be taken literally.
of data in Scheme.
symbols,
lists,
We
+, *, -,
and
and procedures.
Exercises
Exercise 1.6
Using the symbols one and two and the procedure cons, we can construct the
(one two) by typing (cons 'one (cons 'two '())). Using the symbols
list
one, two, three, and four and the procedure cons, construct the following
lists
lists
(you
may
empty
list):
a.
b.
c.
d.
e.
(((one)))
Exercise 1.1
Consider a
Is containing n values.
list
list
If
a evaluates
to any value,
how many
Exercise 1.8
What
1.5
is
'b)? (Try
it!)
Explain this
result.
We
how
to take a
build
new
lists
list
lists
We now
consider
from
old.
We
lists
using two
19
and cdr.'
car applied to
gives the
Is
first
If Is
item in
represents a
Is,
nonempty
list
of items,
Is
gives the
list consisting of all items in Is with the exception of its first item. Both car
and cdr take one operand that must evaluate to a nonempty list. Both car
and cdr are not defined on an empty list, and applying them to an empty list
produces an
error.
nonempty
list, it
returns the
(car '(1 2
[1]
first
When
its
list.
argument
is
Thus we have
4))
It is
ducing what
is
=>
is
other examples of applying the procedure car (As in the previous section, ls4
is
bound
to the
(car
(a b c d))
(car ls4)
list
=>
(car '((1)
=^
(2 1)
(2)
=> (1)
=> ab
pig)))) ^^ ((hen
(3)
(4)))
When
the
list
list is
cow pig))
=>
returned
is
is
first
item (the
is
a nonempty
caur) of the
list,
eirgument
removed. Thus
=*
=>
(2 3 4)
(three 2
1)
The symbol cdr is pronoiinced "coiild-er." The nsmies car and cdr had their origin in the
way the hst-processing language LISP wa^ originally implemented on the IBM 704, where
one could reference the "address" and "decrement" parts of a memory location. Thus car
is an acronym for "contents of address register," and cdr is an acronym for "contents of
'
decrement
20
register."
(cdr '(a (b c)
(d e f)))
=*
((b c)
(d e f))
=*
(cdr '(!))
=*
(cdr '(()))
We now
()
()
By applying
item
=>
(a b c d), we
in the list
car to the
result to get b.
We
we can do
these in succession,
For example,
lists.
we want
if
first
=*
list-of-names be bound
(John Jones)).
we
list.
If
now
get the
car.
We
first
We
let
look at
apply car to
list
how we
retrieve
Jane Doe's
list-of -names, we
to the
get the
finally,
this
We
Doe by applying
get
list
itself.
name from
(Jeme Doe).
last
list
we
((Jane Doe)
list
(Doe) containing
combined
in the
following expression:
(ccir
In this example,
succession a
is
facilitated
number
we
number of
=>
Doe
times.
The
) )
is
in order
from right to
'(a b c))
is
put up to four
.
.
and cdr's
cddddr. The
left.
in
b.
Similarly,
r.
is c.
We make
'
(a
(caddr
We
can
use of these
it
We
menu that
cream. He prepares the menu
list
(chicken
21
We
produce the
list
related items.
We
build the
new
list
=^ chicken
menu) =^ soup
(car menu)
(cadr
=*
'())
(soup)
We now
=^
'()))
^^
(chicken soup)
(ice cream)
We
first
will
make up our
final list.
list
We
use cons to
around the
cream) to get ((ice cream)) and then use cons again to build a
has (chicken soup) as
(cons (cddr menu)
(cons (cons
its first
'())
=^
list
that
second item.
its
((ice cream))
(ceir
=*
The
(ice
list
'()))
'()))
Up
it is
lists.
dotted pair
is
is
b))
=>
while (cdr
a,
book involves
lists,
=>
and
())
(a),
Thus (cons
'(a
b))
'
(a
is
(be))
=>
'b)
b.
(a b c).
Exercise 1.9
If
a and
a.
(ccir
(cons q
/?))
b.
(cdr (cons q
/?))
=*
referred to as a pair.
Exercise
/?
'a
22
the car of the dotted pair, and the second object in the dotted pair
'(a
first
is
=*
Much
pairs.
(a
and (car
work in this
b),
of the
For example,
'
(a
built with
this with
Let us
an experiment.
[1]
(define a 10)
[2]
[3]
(car Is-b)
20
(cdr Is-b)
[4]
(30 40)
(cons a Is-b)
[5]
(10 20 30 40)
a
[6]
10
Is-b
[7]
(20 30 40)
After
all
of these operations involving car, cdr, and cons, the values of the
operands a and Is-b stayed the same when they were entered
as they were
in [6]
and
[7]
far,
be introduced
will
apply to these
The
first
five
in later chapters.
We now
data types.
its
argument
is
a number, and
its
name
is
number?. Like most other predicates, the name ends with a question mark,
signaling that the procedure
number?
#f
is
to
some
object, #t
returned. If
is
is
a predicate.
returned
if
Thus
the object
if
is
definitions,
In
() is
false.
23
we
=
=* #t
num) =^ #t
twelve) ^^
(number? -45.67)
(number?
(number?
(number?
#t
'3)
#f
(number?
(+2
3))
=>
#t
=
=>
#t
#f
is
not a
list,
number.
The
its
argument
is
definitions of
results:
=> #f
^^ #f
'num) =^ #t
twelve) =^ #t
'twelve) ^^ #t
#f) => #f
(symbol? 15)
(symbol? num)
(symbol?
(symbol?
(symbol?
(symbol?
In the
(banaina creaun)))
example, (cdr
Icist
There
'
is
'
(beuieina
also a predicate
=^
^^
#t
#f
cream)
boolean?
evaluates to a
list,
not a symbol.
argument
is
one of
(boolean? t) ==* t
(boolean? (number? 'a))
(boolean? (cons
A
tests
pair
is
'a '()))
=^ #t
=> #f
whether
its
argument
is
a pair.
=^ #t
=> f
'(())) => t
(pair? '(!))
(pair? '())
(pair?
24
We
have
lists
are con-
= t
(cons 'a '())) =* #t
(cons 3 4)) = #t
'pair) =* #f
There
empty
is
also a predicate
null? which
tests
whether
its
argument
the
is
list.
=*
(null? '())
#t
=> t
=> #f
Exercises
Exercise 1.10
If
the operands
oc
and
a.
(symbol? (cons a
b.
(pair? (cons
oc
0))
c.
(null? (cons
o;
/?))
d.
is
/?))
Exercise 1.11
If
list
We
have given
a boolean, or a
a procedure.
argument
is
tests to
list,
There
is
is
a number, a symbol,
also a predicate
procedure? which
tests
it is
whether
its
a procedure.
^^ #f
= #f
(procedure? 'cons)
(procediire? 100)
At
this point,
booleans, pairs,
Apart
is
and streams.
offers
25
Which
upon the information you seek and the data type
a number of these sameness predicates below and in-
We
of the objects.
list
arises.
predicate =
is
When
its
safe to use
It is
it
(= 3 (/ 6 2))
(= (/ 12 2)
(= (car
=^
#t
=>
(* 2 3))
(/ -20 ( 4 5)))
=>
#t
There
is
sameness of symbols.
evaluate to the
#t
#f
'
(eq? (car
'
spects; otherwise
identical
if
we use eq?
it
#t
(eq? (car
The
returns #f
if its
#f
=^
in all re-
they are written with the same characters in the same order. Thus
to test for the sameness of symbols.
new and
On
distinct pair.
Two
alike.
For example,
[1]
[2]
[3]
Then we have
26
operands
#t
^
=
^
this
If its
'(23)))
'(23)))
let
us
make
if
the pairs
(eq? (cons
[4]
'(2 3))
(cons
'(23)))
f
(eq? Is-a '(cons
[5]
'(23)))
#f
[6]
ftf
[7]
#t
In [4]
cons
is
Is-a
by the cons
in [5], so
by the cons
in
evaluates to #f
[2]
.
#f
is
Is-c
Finally,
which
returned.
is
which
distinct
is
lists
is
In [6],
(1 2 3). In [5]
distinct
Is-b
is
returned
the variable
in
[1]
so eq? again
is
same
the
pair,
When we want
and booleans
in the types of
eqv? also
(eqv? (+ 2 3)
(eqv? 5 6)
tests vectors,
(- 10 5))
=>
#t
(eqv? 'cat
=* #f
'cat) =* t
'kitten) =>
(eqv?
'(a a a))
(eqv? 5 'five)
(eqv? 'cat
We
(ccir
lists
among
If
=*
we want a
#t
we can
test for
sameness
lists
(and strings, characters, and vectors), we use the predicate equal?. In the
case of pairs constructed using separate applications of cons, equal? tests the
lists
if
is
returned.
(cons 'a
the same, whereas eq? and eqv? claim that they are
'a
Thus equal?
'(be d))are
diff"erent.
(equal?
'
(a b c)
(equal? (cons
(cons 'a
'(2 3))
(equal? '(a (b c) d)
'
(b c)))
(cons
=>
#t
'(2 3)))
'(a (b c) d))
=>
=>
#t
27
Now
is
is
When
arguments,
its
is
it
is less
the most efficient predicate. For testing only numbers or symbols, eqv?
more
than equal?.
efficient
limited to numbers,
When we
When we know
we use
shall be using
When
numbers
the discussion
=.
returned. If
is
is
(1 2 3) by entering (car
list
printable.
is
we
'
1 is
is
On
is
the other
If
is
is
returned,
displayed. In general,
We now
we
such as car to a
name
that
is
the
one to use?
its
first test
#t
numbers, =
eq?
a predicate
efficient
#f
must
'(a (c b)))
when we
use <som-symbol>,
it
is
denotes a procedure.
some facts that apply to their use. The list is certainly not all inclusive,
and we recommend that you add your own entries to it to reinforce your
understanding of the use of predicates. Let a and /? be operands such that a
evaluates to any value and f3 evaluates to any nonempty list. We then have:
writing
The number
items in
/?.
(eq? a
/?)
of items in (cons
=>
/?)
is
#t
implies
(eqv? a /?)==> #t
implies
(equal? a
(eq? (cons a
f5)
/3)
#t
=*
=* #f
/?)) =* #t
/?))
(cons a
/?)
==> #f
(3))
(cons a
(boolean? (eqv? a
=*
(cons a
(eqv? (cons a 0)
(equal? (cons a
/?)
#t
=>
#t
/?))
/3)
(cdr
/?)
=>
(3))
a)
^^
(3))
(3)
=i* #t
(null?
13)
(pair?
13)
=>
=>
#t
#f
#t
(pair? (cons a
=i> #t
(3))
We
#t
=^
#t
five basic
compute with
and
lists,
in
Chapter
we
shall
do the same
for
numbers.
Exercises
Exercise 1.12
Evaluate each of the following.
a.
b.
c.
(3 4)
(5 6))))
d.
(3 4)
(5 6))))
e.
f.
(cadr '(a b
g.
(d e)))))
d))
Exercise 1.13
We
list
(car (cdr
'
(b (a c)
symbol
lists,
steps:
'
(b
=>
d)))
((a c) d)
=>
(a c) d))))
(a c)
^^
a:
29
a.
(b c a d)
b.
((b a)
(c d))
c.
((d c)
(a) b)
d.
(((a)))
Exercise 1.1
Decide whether the following expressions are true or
a.
b.
c.
d.
e.
f.
false:
'()))
Exercise 1.15
Decide whether the following expressions are true or
30
(b a))))
a.
b.
c.
d.
e.
f.
g.
h.
'
(car (cdr
(b c))
'
(b c))
'
'
(cons 'a
'
(cons 'a
(b c))
(b c)))
'
(cons 'a
(b c)))
'
(b c)))
false:
2.1
Overview
we used
several
2.2
Procedures
The notation f{x,y)
name / and hcis two
is
variables, x
and
y.
We
call
is
it
has the
To each
In computing,
we
are concerned
putational steps that we perform to get the value returned by the function as
an algorithm for computing the function's value. The way we implement the
algorithm on the computer to get the desired value
is
y,
we use a
value. Iff
is
name
the
list
in
name
whole
is
number
we
have already seen the procedure cons takes two arguments, and the procedure
+,
all
procedures needed.
Therefore,
is
provides an elegant
way
write (cons
Now
We
illustrate
When we write
we
it
Scheme
It is
let's
'bit
'()),
we
get a
list
list
its
only element.
We
it,
(19). If
it,
namely (bit).
list
containing the
it
with a lambda
do
expression,
(leuabda (item)
lambda expression
identified
If
is
(bound
is
Then the
lambda expression)
The value of the body
lambda expression
body of the
to 19.
in this Ccise
it
is
is
lambda.^
keyword lambda,
is
assigned
so obtained
is
is
(19). In
is
to
Speciad forms look like applications but are not, and in order to recognize them, we have
but the
S2
We
keywords
later,
(Icimbda (parameteT
is
followed by a
body)
list
list
The
contains zero
more parameters. The next subexpression is the body of the lambda expresThe value of a lambda expression is the procedure, which can be applied
to values appropriate for the evaluation of the body. These values must agree
in number with the number of parameters in the lambda expression's parameter list. When the procedure is applied, the parameters are bound to the
corresponding values, and the body is evaluated. The value of the body is
or
sion.
when a procedure
In general,
is
(operator operand
where operator
plied,
is
is
is
applied.
We
operator
is
The
value of the
6.
list
containing the
'bit)
awkward
6.
It is
1)), the
(-7
5 6))
=J> (30)
procedure a
name and
2.2 Procedures
using that
name
We
in the
S3
is
We
and
its value.
write
This
easier to read
is
if
clearly
on separate
lines as
follows:
(define make-list-of-one
(leimbda (item)
Scheme ignores any spaces in excess of the one space needed to separate
expressions. Scheme also treats <RETURN>'s as spaces until the one following
the last right parenthesis that
is
first left
parenthesis in
application
(make-list-of-one 'bit)
and (bit)
We
is
returned.
Computer programs
to
list
more complicated,
As the
tasks
become
is
a series of learning experiences that will prepare you not only to be able to
write such programs but to do so in a
way that
is efficient,
elegant,
and
clear
to read.
word
is
in order
many
characters in
as
easier,
$4
it
and parameters.
we wish, programs will be
for procedures
is
closing.
is
list
to be included in the
Now
list.
let's
In the
list
ar-
The
is:
(define make-list-of-two
The parameter
list
in the first
When Scheme
it
ignores
all
This allows us to make remarks about the program so that the reader
looking at
will
it
know
names of variables
follow the
program
in this book,
We
each line
is
wish to
accompanying
By choosing
also precede or
When we
unnecessary.
in the
we
if
easier.
carefully,
them
and
make
discussion.
two by writing
(mcJce-list-of-two 'one 'two)
When we
=*
(one two)
When we
its
two arguments were the values of the operands 'one and 'two.
In Section 1.5, we saw how to take a list containing four items (menu was
bound to the list (chicken soup ice cream)) and build a new list containing
the same items but grouped into two lists, each containing two items. We can
use the procedure make-list-of-two to give us another way of doing that
grouping. We define a procedure called regroup that has as its parameter
list-of-4, which will be bound to a list of four items. It returns a list with
the items in list-of-4 regrouped into two lists of two items each. In the
2.2 Procedures
35
we
shall find
we
create.
define
We
it
we want
clearer to
make
to appear in the
that follows,
where
it is
we make use
it
later. In
the definition
first-group and
second-group.
(define regroup
(lambda (list-of-4)
(mcike-list-of-two
(first-group list-of-4)
(second-group li8t-of-4))))
item being a
is
used to create a
consisting of the
list
last
two items
first
in
two items
list
in
we
first
define as:
(define first-group
(lambda (Is)
(meike-list-of-two (car Is) (cadr Is))))
We
second-group
as:
(define second-group
(lambda (Is)
(cddr Is)))
When first-group is
the
list
list
consisting of the
items.
the
list
last
two items.
Now
to get the
is
(regroup menu)
first
first
two items
bound
is
two, that
is,
the
=*
list:
to
applied
list
rest of
consisting of the
36
to menu,
What
ter
forth?
is
in
The
version in Chapter
1 is
in
Chap-
in
it is
scanned, for
we have to pause to work out what the constructors and selectors are doing.
In the new version, you can look at the code for regroup and see immediately
that
it
making a
is
items, the
list
first
list
two items
first
group
list
is
again a
to read
easier to understand.
many programs.
we happen
to
is
By carefully
make the pro-
of four items.
program
of two
grams easy
list
make
the
in writing
We have defined
procedures to build
lists
Scheme provides a procedure list, which takes any number of arguments and
constructs a
list
=> (a b c d)
4)) =* ((1 2) (3
We
=*
shall see
'(3
4))
()
how list
is
defined in Chapter
7.
ming. In both, we are looking for the solution of some problem and want to
write a procedure that returns the desired solution as
its
we
main procedure. In top-down style, we first write the defimain procedure. The main procedure often uses certain helping
procedures, so we write the definitions of the helping procedures next. These
in turn may require other helping procedures, so we write those, and so on. In
bottom-up style, we first write the definitions of the helping procedures that
we anticipate using, and at the end, we write the main procedure. We shall
use both styles of programming in this book.
We summarize this discussion by observing that the value of a lambda
refer to this as the
nition of the
(lambda (parameter
body)
a procedure. The ellipsis after parameter means that this is a list of zero or
more parameters. When the procedure is applied, the parameters are bound
to the arguments (i.e., the values of the operands), and the body is evaluated.
is
2.2 Procedures
37
We
name by
structure
where procedure-name
We
is
name
named procedure by
{procedure-name operand
of the procedure.'
when an
{operator operand
is
in the def-
all
specified order.
the
is
and
it is
arguments, that the procedure receives, we say the operands are passed by
value to the procedure.
We
have also encountered two expressions that are called special forms:
those with the keywords define and lambda. These expressions are not applications because not
all
and
its
body
is
not evaluated
initially.
list is
'
Scheme the number of such keywords for special forms is relatively small.
Chapter 14, we shall see how we can add to Scheme our own special forms.
Scheme
also supports
38
never evaluated
Exercises
When
may
find
it
file.
They can be entered into Scheme from a file in which they were saved either
by using a transfer mechanism or by invoking a loading procedure. In some
implementations of Scheme,
Exercise 2.1:
this
is
second
list.
Assume
argument a
its
that the
list
list
and that
items.
Exercise 2.2:
third
Assume
list.
its
that the
argument a
list
list
and that
items.
Exercise 2.3:
The procedure
(define
f irsts-of-both
f irsts-of-both
is
defined as follows:
f irsts-of-both
(ceur
list-2))))
(f irsts-of-both
b. (f
'(1357) '(246))
Exercise
2.4-'
juggle
juggle returns a
first
list
is
The procedure
list
so that the
element of this
third,
that
list.
list
2.2 Procedures
39
switch
Exercise 2.5:
three-element
list.
exercise.
The
list,
or a pair,
tests
whether a value
a number,
the value
is
If
the value
is
an empty
If
the value
is
If
the value
is
list,
is
its
type.
as:
This description of the procedure using English gives a sequence of steps that
we
computation
given in
we
tl
called an algorithm.
cond).
We
is
its
(cond
((pair? item) 'pair)
((null? item) 'empty-list)
Let us analyze the cond expression. In this case, the cond expression has
five clauses,
first clause, (
which
is
(pair? item)
'pair), has as
its first
is
or
is
If
not a pair.
We
pair
40
is
returned.
If
first
is
evaluated and
is
and
expression,
first
following else
else
is
returned.
is
The
is
'empty-list)
last clause
evaluated.
is
consequent
is
evaluated
its
if all
evaluated, and
its
value
is
returned.
The
expression following
is
(cond
{conditiorii consequenti)
{condition2 con3equent2)
iconditioun consequentn)
(else alternative))
where
for each k
and
l,...,n,
is
the
same
If
cases.
We
is
is
true, the
in the last
else clause.*
can also use the special form with keyword if. Suppose we
argument
is
Here
is
(define car-if-pair
(lambda (item)
(cond
* The else clause is optional. Hit is omitted and all of the conditions are false, then Scheme
does not specify the value that is returned as the value of the cond expression. We shall
avoid using cond expressions that return unspecified values.
4.I
or using an
if
expression,
it
can be written
as:
(define ceur-if-pair
(leunbda (item)
(if
(pair? item)
item)
(c2u:
item)))
if
expression
is
or
In the
first case, if
if
condition
is
expression;
native
is
is
unspecified value
If
condition
if
if,"
if
condition
if
expression.
is
is
returned as
expression.
In this "one-armed
consequent
is false,
not present.
of consequent
if
is
If it is false,
an
returned.
(define type-of
(lambda (item)
(if
(pair? item)
'pair
(if (null? item)
'empty-list
(if (niimber? item)
'number
(if (symbol? item)
'symbol
'
Any cond
some-other-type)
) ) ) )
if
42
if
num-
The
evaluating a condition.
or
it
may
The
condition
may
first
is
its
of two or
The syntax
'cat))
is
given below:
The and
exprn in succession.
If
is false, it
.,
is
#f
If all
is
of the
returned
The
exprn
If
is
true,
it
true subexpression. If
or expression
is
is
#f
We
all
expression
is
and and or
in the following
it is
examples:
(define s-eind-n-list?
(lambda (Is)
(euid
(pair? Is)
Scheme has a convention of treating einy value that is not false as true. Thus (if 'cat
'kitten 'puppy) ^^ kitten, since the condition 'cat evaluates to cat, which is not false.
It is good programming style, however, for the conditions to be boolean expressions that
evaduate to either tt or tf
^
4^
The
The value
as its argument.
list
is
#t
of
if:
some-list is a pair,
and the first item in some-list is a symbol,
and the cdr of some-list is a pair,
and the second item
in
some-list
is
a number.
(s-and-n-list? '(a
is
=*
D) =
#f
b))
#f
For example,
while
(s-and-n-list? '(a b
The
test to
If
the
list is
list is
a pair
is
necessary since
we can only
first false
value.
(define s-or-n-list?
(lambda (Is)
(and (pair? Is)
(or (symbol? (cau: Is))
The
(s-or-n-list? some-list)
some-list
and
is
=^ #t
some-list
list
is
is
a symbol or
test
whether a
a singleton
whether
element,
it
it is
Program
enough to
2.1
test
whether
list.
its
list
It
contains precisely
is
easy to define
argument
is
a pair and
test
cdr
is
(lambda (Is)
a number.
its
singleton-list?
it is
To
(define singleton-list?
44
=* #f
is,
as its
a pair,
list
if:
nonempty
a singleton
list
whose cdr
is
list is
and
is
thus
list.
Exercises
Exercise 2.6
Assume
that
a, b,
and
are expressions that evaluate to #f. Decide whether the following expressions
are true or false.
be))
a.
(and a (or
b.
c.
d.
be)))
Exercise 2.1
Decide whether the following expressions are true or false
if
expr
is
some
boolean expression.
a.
b.
c.
d.
Exercise 2.8
Decide whether the following expressions are true or false using s-cind-n-
list? as defined
in this section.
a.
b.
(s-and-n-list? '(b 4 u
c.
d.
(s-and-n-list? '(a))
c a j))
Exercise 2.9
Decide whether the following expressions are true or false using s-or-n-list?
as defined in this section.
a.
(s-or-n-list? '(b))
^5
b.
(s-or-n-list? '(c
c.
d.
(s-or-n-list? '())
2 m))
2.4 Recursion
We saw
When
we
body
of the lambda
we say that the procedure is recursive. To introduce the
idea of a recursive procedure, we set as our goal the definition of a procedure
last-item. that, when applied to a nonempty list, returns the last top-level
ing procedures.
expression defining
item
in the
it.
list.
(last-itea
'(12345))
(last-item '(a b
(last-item
(last-item
It is
(c
d)))
'(cat)) =>
'((cat))) =^
=*
=^
(c d)
cat
(cat)
good idea to begin with the simplest cases of the arguments to which
the procedure
is
applied.
and applying
both
its first
list
and
if
the
list is
nonempty
list
is
list
produces the
last item.
is
This
When
How
can we
test
whether Is
its
cdr
is
the
We
list
(define last-item
(lambda (Is)
(cond
46
)))
list
if
that
is
the
If
we now consider a
of that
list
list
of the original
list
we have a
we
have a
finally
solution.
list
cdr to the
The
item.
example, the
Icist
list.
still
item,
last
(a b c) and the
list
Thus
c.
we
if
call
list
we
the
all
same
is its
last-item
cdr,
as a helping procedure
else clause to
(b c), which
the procedure
we add the
is
list
list
list,
last-item,
contains
more than
one item:
Progreun 2.2
last-item
(define last-item
(lambda (Is)
(cond
To
s))))))
Then
which Is
is
list
nonempty
list
Is,
last
list
(which
is
first
cond clause
is
Now
let's
true,
list.
and
(ceir
Thus last-
its cdr,
(b), contains
one item, so the procedure last-item does work on (cdr Is), allowing us to
it as a helping procedure in the else clause to get the correct result. Thus
last-item solves the problem for any list of two items. Now we use the fact
that last-item works on the cdr of any three-item list to conclude that it
use
^ It is
evaluating.
We
2.4 Recursion
it
first iten> is
context
is
4^
works on the three-item
list itself.
problem
for
any
We
list.
item
is
a recursive procedure.
procedure on a
list is first
Our strategy
in general in
designing a recursive
sion that solves the problem for that case as the consequent in the
clause.
We
call this
first
cond
We
Then
in
the
list
The
last-item
we
list.
procedure as a help-
simplifying operation
to the simplified
is
cdr, and in
is
problem applies
(cdr Is).
list
(cdr Is)
is
is
is
evaluated.
tells
us to apply
'
(last-item
'
(c)).
We now
consequent
The
'
(c)
base case.
call
is
'(c))
is
the
empty
Thus the
list.
when
the
first
list is
simplified to the
cond clause
is
true.
is
is
We
In
Generally,
must be
included so that the recursion will eventually stop. (In Chapter 15 on streams,
we
shall see
examples
in
is
not needed.)
We
condition as the
first
cond clause.
We
definition.
we introduced the
of an expression by substitut-
substitution model,
48
Through the
model
From Chapter
suffices.
first
when the
model does not work. From time to time, we use it to clarify a computation; most of the time, however, we use the general approach:
the environment model. In that approach we just remember the bindings of
substitution
argument
is
its first
second
2.
3.
4.
(member?
5.
Example
In
returned.
3,
We
'
(2 3)
is
'
=*
=*
=>
#t
#f
(2 3) 4), so #f
(1
list
is
is, if
Is
is
the
empty
list,
#f
is
To
returned. This
is
#f
We
is
the
#f
#f
(2 3) 4))
(1
=*
is
(define member?
(leunbda (item Is)
(cond
((null? Is) f)
...
Now
)))
given any
list,
what
is
empty list? It is again the procedure cdr. Assume that Is is not empty.
we know the value of (member? item (cdr Is) ) how do we get the value
for (member? item Is)? Well, when is the latter statement true? It is true
if either the first item in Is is the same as item or if item is a member of
the
If
list
following the
first
item.
expression:
Thus
in the case
2.4 Recursion
when Is
is
is
true exactly
4^
when
nition of
true.
is
We
defi-
member? with
Program
member?
2.3
(define member?
((null? Is) f)
(else (or (equal? (car Is) item)
(member' item (cdr Is)))))))
'
is
recursive since
it
(null? Is)
is
we look
erwise
in Is or if
true, then
is
in
is
When member?
calls itself
item
to the value of
item
is
is
true
if
otherwise
either
is
a shorter
list
is
is
Oth-
the
item
first
its
parameter
is
bound
item
is false.
false.
calls itself.
the
call,
shorter,
list is
(null? Is).
In order to use a
list
as the
first
argument to member?
(as in
Example
4),
we used the predicate equaJ.? to make the sameness test in the else clause. If
we know that the items to which item is bound will always be symbols, we
can use eq? in place of equsd.?. The procedure so defined using eq? is named
memq? to distinguish it from member?, which is defined using equatl? for the
sameness test. Similarly, if we know that the items to which item is bound
will always be either symbols or numbers, we can use eqv? for the sameness
test
and
We
call the
level
item out of a
item
is
list,
list.
We
tests
last top-
whether
continue illustrating
how
ein
to
Scheme provides the three procedures member, nemq, and memv, written without the quessomewhat differently from the ones we defined with the question
mark
in that
whose car
50
is
if item is not found, false is returned, but if item is found in Is, the subUst
item is returned. For example, (memq 'b '(a b c)) ^^ (b c).
manipulating
for
lists.
list
the
top-level
first
1.
^*
2.
=>
3.
4.
5.
(remove-lst '(1 2)
=*
=*
'(1 2 (1 2)
>
((1 2))))
(1 2
((1 2)))
and a
list
Is. It builds a
We
it.
the empty list. Since item does not occur at all in the empty list, the
we build is still the empty list. The test for the base case is then (null?
Is), and the value returned in its consequent is (). Thus the definition of the
procedure remove-lst begins with
Is
is
list
(define remove-lst
(Isunbda (item Is)
(cond
((null? Is)
...
If
Is
is
'())
)))
it
is
again
list
consisting of the
writing
2.4 Recursion
51
(define reaove-lst
'())
...
The only
case
top-level item
left
to be considered
is
when Is
is
is
item
its first
not
is
c.
by removing
from (b
c d).
and has
in
it
'
this
)
(remove-lst
are building
'c
list
is
is
the
first
element of Is
top-level occurrence of
(a b c d). The
Program
final
list
list
(a b c d))
we
list
The
its first
given in
is
Program
2.4.
remove-lst
2.4
(define remove-lst
(lambda (item Is)
(cond
((null? Is)
'())
To
how
(remove-lst
52
'(abed))
the verb cons, which has am infinitive "to cons", tenses "cons,
make
'c
and conjugation
"I cons,
he conses,
etc."
We
shall
Since the
list
(a b c d)
is
is
entry
is
not
c,
the alter-
To
first
'(bed)))
we must evaluate the remove-lst subexOnce again, the list (b c d) is not empty, and the first item in the
not the same as c. Thus the alternative in the else clause is evaluated.
pression.
list is
Once again,
lst subexpression.
Now
the
list
(c d)
is
its first
item
is
the
same as c. Thus the condition in the second cond clause in the definition of
remove-lst is true and the value of its consequent is (d). Thus the above
expression has the value
This
see
is
how
we
shall
In order to be able to
5,
call.
remove a
sublist
from a given
list,
as in
Example
the predicate equal? was used to test for sameness in the second cond
we know that all of the arguments to which item will be bound are
symbols, we can use eq? to test for sameness. The procedure defined using eq?
instead of equal? is named remq-lst. Similarly, if we restrict the arguments
to which item will be bound to symbols or numbers, we can use eqv? to test
for sameness in the second cond clause, and we name the procedure so defined
clause. If
remv-lst.
Exercises
Exercise 2.10
Rewrite the definitions of the three procedures last-item, member? and
2.4 Recursion
if
expressions.
53
Exercise 2.11
The
definition of
else clause.
member? given
an or expression
in the
handled
is
in a
Compare
Exercise 2.12
The
named mystery,
following procedure,
takes as
its
argument a
list
that
(define mystery
(Icunbda (Is)
(if
What
ior of
is
'
'
Exercise 2.13:
for the
procedure mystery.
subst-lst
list
of items Is.
in
Is and replaces
it
first
'b
'a
'
(c a b a c)
^=> (c b b a c)
(subst-lst '(0)
'()
'((*)
(1)
=
(subst-lst 'two 'one '())
lists
eters
are
()
((0)
(2)))
(1)
()
as possible
(2))
sameness.
Also define
procedures substq-lst and substv-lst that use eq? and eqv? respectively,
instead of equal? to test for sameness.
54
insert-right-lst
The procedure insert-right-lst is like remove-lst except that instead of
removing the item that it is searching for, it inserts a new item to its right.
Exercise 2.14:
For example,
(insert-right-lst 'not 'does '(my dog does have fleas))
=>
The
definition of
insert-right-lst
is
(define insert-right-lst
new item
insert-right-lst except
is like
it is
searching
Exercise 2.15:
^^
=>
(a a b c a b c)
()
list-of -first-items
composed of nonempty
lists
is
list
its
argument a
composed of the
list
first
(list-of -first-items
(list-of-first-items
(list-of-f irst-items
(list-of-first-items
2.4 Recursion
'((one)))
'())
=*
^^
(one)
()
55
Exercise 2.16:
replace
list
of items
Exercise 2.17:
^^
^^
^^
remove-2iid
item a from a
list
of items Is.
You may
(re2cve-2iid 'cat
Exercise 2.18:
remove-last
list
Exercise 2.19:
sandwich- 1st
Is as
its
arguments.
Is with b a
b.
It
replaces the
first
occxirrence of
b.
and a
two successive
list
b's in
56
=^
Exercise 2.20:
list-of-symbols?
a given
in
list
using
first
cond, then if, and finally and and or. Test your procedures with:
Exercise 2.21:
all- same?
whether
all
=>
(all-same? '((a b)
(all-same? '(a))
(all-same? '())
2.5 Tracing
list
Is as
its
argument and
tests
(a b)
=>
#t
#f
(a b)))
=>
#t
#t
and Debugging
We
We
The
technically
tool
known,
its
We
The computer
power to
as to
is
which
able to do
relieve us of this
kind
it
is
of arguments.
its
we make
arguments
computer
screen.
its
if
When we
A more
is
presented in Chapter
if
evaluate
complete discussion of writeln and related procedures that write to the screen
7. You may enter the definition of writeln given in Program 7.5 if
your implementation of Scheme does not provide it.
57
exprn are
them.
When
the next
line.
left
...
all
exprn)
is
is
For example,
Punch
is
bound
if
is
bound
to the value
will print
JudyJill
If
We
we want
it
by a backslash.
which
hcis
".
is
string
is
if
we use
" is
an example of a
string.
we must precede
^'^
If
then
This is a string.
appears on the screen. Note that the double quotes are not printed with the
string.
cheu-acter,
follows
58
it is
referred to
is
is
an escape character.
prints
He said "Hello".
string
is
if
we
enter a
is
quotes.
[1]
"This is a string."
"This is a string."
If
we evaluate
(writeln "My friends Jack and
we
see
"
Jack ".")
on the screen:
is
is
is
is
subexpression
[2]
is
it
is
last
(begin
(12
3 4)
59
When
The
evaluated consecutively.
expression
ignored.
is
The
evaluated.
The value
a begin expression,
screen), but
all
is
that
is
it is
is
is
is
done as a side
is
returned.
and not
each writeln
last line.
some change
what
new
the
effect.
screen, with a
arguments on the
their
first
is
change
When
using
The
value of
Here
is
another example to
is
returned.
[3]
is
(begin
(+ 3 4)
(- 5 11)
(* 10 10))
100
The
values of the
first
evaluated,
it
We now
have
all
last one,
the tools
we need
...
and there
really
was no point
in
exprn)
...
expTn,
to use
returned.
is
writeln
We
it
The definitions of
main program. The procedure
entering takes three arguments: the value of the condition, the value of Is,
and the identifying number of the cond clause: 1 for the first, 2 for the second,
and
are entering
60
It tells us,
and the value of Is. The procedure leaving takes two arguments:
cond
number
of the
clause. It tells us
When we
consequent.
time we enter or leave a cond clause. Inserting such writeln expressions into
the definition of a procedure to study the evaluation of the procedure
way
The
Program
test
is
true,
is
bound
it
is
is
else as the
true (since
is
If
entered. If
is
true, the
is
entered,
a leaving expression.
number
test
It
When
is
2.7.
remove-lst.
is
If
test
is false,
evaluated.
result.
Program
entering
The consequent
in
first
it is
is
is
clause
parameter test
one
2.6,
When we
If
Program
is
is
evaluated,
its first
it tells
parameter,
us the identifying
is
bound.
It
then
returns result.
Now
let's
helps us see
[1]
what
is
(remove-lst-trace
'c
'(a b c d))
c d)
c d)
(c d)
This output
tells
to (a b c d).
us that
With
evaluated, so that
we
first
bound
its first
operand
is
(1)
61
Progrson 2.5
remove-lst-trace
(define remove-lst-trace
1)
(leaving '()!))
((entering 'else Is 3)
(leaving
(cons (car Is) (remove-lst-trace item (cdr Is)))
3)))))
Program
2.6
entering
(define entering
Entering cond-clause-"
"
cond-clause-number
"
with Is =
"
input))
test)))
Program
2.7
leaving
(define leaving
(leuobda (result cond-clause-number)
(begin
cond-clause-number
result)))
62
"
with result =
"
result)
evaluated.
is
is
and a
called again,
waiting to be
is
consed onto the value obtained before we can leave cond clause
tells
3.
The next
us that
evaluated, and b
cond clause
As
3.
is
remove-lst-trace
before,
writeln expression
is
is
(2)
value before
its
item
same
with Is bound
in (c d)
c,
we
is
Cons expression
We
which
us that
tells
But
this
is
the
in the leaving
result bound
to (d),
returned.
(2)
is
is
d).
Then
leave
we can
With this
call,
we
result bound
is
to (b
its
we
invocation
now
its
result bound
to (a b d).
We
see that
we do not
recursive invocation of
we
enter
is
call.
The leaving
The
trace
we made
is
found
clauses.
for the
illustrates:
63
(remove-lst-trace
[2]
'e
'
(a b c d))
(abed)
(c d)
c d)
(abed)
Analyze the trace to be sure you can explain
it
in a
manner
similar to that
We
a program
is
It is
at that place.
is
being
it
to do,
expression at certain places in the program where you think the error
and look
made
may
be
that place.
of the error
correctly.
When
the program
is
is
tool.
Exercise
Exercise 2.22
In the
first trace,
64
first
In the
Can you
give
The
last
example of recursion
in this chapter
and y
an item
in
list
x,
is
is
and a
y,
in
Is
replaced by x.
is
list
Is.
It
builds
replaced by y, and
We
are "swapping" x
For example,
in Is.
'
(a b) d)
(c
=*
(c
(a b) d)
()
and b
not at top
level, so
they are
not swapped.
In order to define swapper,
What
to
is
the
we begin with an
empty
list,
list is
returned.
If
Is
empty, there
Thus we take
cis
is
nothing
definition as follows:
(define swapper
(lambda (x y Is)
(cond
((null? Is)
'())
)))
...
A nonempty
list is
What
ation cdr.
is
returned
if
(cdr Is) with the items x and y interchanged. But this differs
from (snapper x y Is) only in that the first item in (swapper x y Is) is
result will be
missing.
We
will get
first
it
can be
x, y, or neither. First, if
X,
in
(car Is)
is
(leunbda (x y Is)
(cond
((null? Is)
'())
2.5 Tracing
)))
and Debugging
65
Program
2.8
swapper
(define swapper
(lanbda (x y Is)
(cond
((null? Is)
'())
Second,
if
(car Is)
is y,
(define swapper
(lambda (x y Is)
(cond
((null? Is)
'())
...
Finally,
if
(car Is)
is
Program
we
else clause
2.8.
If
d b).
it
list
first
its
procedure
car
is
call,
'd,
and '(a
answer. In the
'b,
Is
is
bound
constructs this
it
to (a b c d b). This
is
list is
evaluated and
'
(b c d b)
and that
is
the
value that we are looking for to solve the problem. At this point, however.
66
we have not
value the
its
We
answer- 1
is:
answer-2
is:
is
'(bed
b))
move on to
answer-1 when
answer-2
rewrite answer- 1 as
we
known.
is
is
that the
list
(b c d b) begins with b, so
its
consequent gives us
We still
until
answer-1
is:
answer-2
is:
answer- 3
is:
we have a value
for
for answer-3.
various answers, with each successive entry placed below the preceding one.
We
To
give
it
the
begin with b or
for
we
d, so
is
name
return table.
is
evaluated.
We
get
answer-3
(cons 'c (swapper 'b 'd '(d b)))
and we give the invocation of swapper within answer-3 the name answer-4This gives us the return table:
We
answer-1
is:
answer-2
is:
answer-3
is:
answer-4
is:
(d b))
have added answer-3 to our return table to wait until we have the value
of answer-4
We
'
is
now becomes
answer-1
is:
answer-2
is:
answer-3
is:
answer-4
is:
answer- 5
is:
have added answer-4 to our return table to wait for a value for answer-5.
67
cond clause
is
now becomes
answer-}
is:
answer-2
is:
answer-3
is:
answer-4
is:
answer-5
is:
answer- 6
is:
we
In the invocation of
cond clause
first
is
swapper
true,
in
answer-6, the
()
is
What
effect
have a value for answer-6 the computation does not stop, for we have to get
,
Until now,
on each recursive invocation of swapper, a new row was added to the return
table waiting for a value.
not have to add a row to the return table. Instead we replace the swapper
expression in the last row by
its
value
( )
We
can
the table one row at a time, replacing each variable on the right side by the
value
new
The
it
We
last
answer-6
is:
answer-5
is:
(d)
answer-4
is:
(b d)
answer-3
is:
answer-2
is:
(d c b d)
answer- 1
is:
(a d c b d)
()
[c
b d)
for
Let's take another look at the definition of the procedure swapper. In the
last three
is
consed onto
What
Is).
We
is
68
test
and
test procedure,
we can
(define swapper
(lambda (x y Is)
(cond
((null? Is)
'())
We now
swap-tester
(define swap-tester
(Icunbda (x y a)
(cond
((equal? a x) y)
((equal? a y) x)
(else a))))
When swap-tester
is
arguments
x,
y and
x, y,
a, respectively,
and icax
and swap-
The
use of such helping procedures often simplifies the writing and reading of
programs.
We
We
shall
make
could also have achieved the same effect without using the helping
tester
in place of calling
swap-tester.
swapper:
(define swapper
(lambda (x y Is)
(cond
((null? Is)
'())
69
In this section,
debug a program.
recursive procedure
We
is
is
created
when a
evaluated.
Exercises
Exercise 2.23
Identify
what
is
what
is
following:
a.
(begin
(writeln "(* 3 4) =
(=
b.
c.
3 4)
(begin
(writeln
(writeln
(writeln
(cons 'a
"
( 3 4))
12))
"(cons 'a '(be)) has the value " (cons 'a (b c)))
"(cons 'a (b c)) has the value "
(a b c))
"(cons 'a (b c)) has the value (a b c)")
'
'
'
'
'(be)))
(begin
(writeln "Hello, how aure you?")
(writeln "Fine, thanX you. How are you? " 'Jack)
(writeln "Just great! It is good to see you again,
"Good-bye. Have a nice day.")
Exercise
2.24-'
With describe
"
'Jill)
describe
defined as
(define describe
(lambda (s)
(cond
((null? s) (quote '()))
((nunber? s) s)
((synbol? s) (list 'quote s))
((pair? s) (list 'cons (describe
(else s))))
70
a.
(describe 347)
b.
(describe 'hello)
(ceir s))
c.
d.
(describe
'
(d e) f g) h))
(a (b c
Exercise 2.25
Write a trace similar to the one used in remove-lst-trace to trace the procedure swapper, showing the binding of the parameter Is each time the cond
expression
is
is
b, d,
and (a b
d b) used
in
Exercise 2.26
In the return table built for the invocation of
swapper
computation did not stop when the terminating condition was true and the
first
( )
first
an operation to perform
after
still
way because
had to be completed.
after each
There was
still
analysis,
Program 2.2
consider (last-item
(a b
and member?
in
Program
2.3.
In the
first case,
is
'
'c
'(abed)).
In these
in the
We
shall
chapter on
numerical recursion.
Exercise 2.27
if
2 are interchanged in
if
cond clauses
and
swap-tester?
tracing, test-tracing
more generally applicable tracing tool than the procedure leaving given
Program 2.7 is the procedure tracing defined by
Exercise 2.28:
A
in
(define tracing
result)))
71
test-tracing defined by
(define test-tracing
test)))
is
Rewrite the
72
3.1
Overview
Many
of the procedures
we studied
in
Chapters
and
2 operated
on
lists
We
also develop a
us-
ing fractions instead of decimals, which are usually associated with computers.
This
3.2 Operations
will
on Numbers
We
inte-
...,-4,-3,-2,-1,0,1,2,3.4,...
where, in this case, the
ellipsis
list
continues indefinitely in
both directions.
The
bers
set of real
and
zero.
positive
all real
We
The number
real
write real
is
system dependent.
fifteenth digit,
that 2.735
to the
wise.
is
moved two
places
left.
We
The
is
use two predicates, integer? and real?, to test the type of a number.
integers,
and
otherwise
is
false.
true
is
is
if
true
num
if
num
is
is
an integer and
any
real
false other-
number, including
itive?, and negative?, which make the obvious tests to see whether their
arguments are
The
* for multiplication,
and
/ for division. These are applied to numbers with applications, as were the
list
we
operations in Chapter
2.
(- 4 32)
(*
==>
is
7,
returned. Similarly^
- 28
-15 -3)
45
(/ -15 -3)
(/ -16 -3)
5.
We recommend
33333333333333
many
than entering (+ n
1),
(addl 7)
=> 8
=*
(addl -37)
When
division
is
-36
0.66666666666666.
74
Program
addl
3.1
(define addl
(IckBbda (n)
(+ n 1)))
Program
subl
3.2
(define subl
(lembda (n)
n 1)))
(-
Not
its
all
definition in
Program
3.1.
Similarly the predecessor procedure subl can be used to get the integer
that precedes a given integer.
=> 6
-37) =^
(subl 7)
(subl
-38
list
about each.
When
We
present
may
or
may
not be
numbers, eqv? and equal? both determine the type and apply the appropriate
sameness
When
test.
are numbers,
it is
it is
known
to
is
specifically designed to
compare numbers.
When
apply to
testing for 0,
The computer's decimal representation 0.333333333333333 for the quotient (/ 1 3) is not the same as the fraction 1/3 but is, rather, an approximation to it, the use of which is made necessary by the way real numbers are
represented in the computer. Thus we would not expect = to return true if
we test (/ 1 3) and 0.333333333333333. In general, because the internal
representation of certain numbers in the computer
to the actual
sider
number, we
numbers
refer to
is
only an approximation
We
con-
3.2 Operations on
Numbers
75
Remarks
Expression
(=
m
m
n)
n)
Tests whether
m is less
than n.
n)
Tests whether
than or equal to n.
m n)
(>= m n)
Tests whether
m
m
m
(abs n)
(<
m
(>
Tests whether
=^
(abs -5)
(ceiling n)
is
less
is
greater than n.
is
^^
(abs 5)
n.
5.
(ceiling 5.3)
(floor n)
=^
6.
(ceiling -5.3)
(floor 5.3)
Rounds n
(round n)
5 and
(floor -5.3)
5.
is
it
<
>
n.
-5.
n.
-6.
is
If n
rounds
is
it
(truncate n)
off
(expt n
/:)
The square
(sqrt n)
(meuc
(exp n)
.)
(nin n
(log n)
..)
e,
(sin n)
(cos n)
root of n, n
The maximum
The
The
k.
<ind
>
0.
minimum
of n
.,
respectively.
(n in radians).
(asin n)
(acos n)
The
arc sine
(tan n)
The tangent
(atan n)
The
ajc tangent of n.
(quotient n k)
The
quotient of n divided by
(remainder n k)
The remainder
n, respectively.
of n (n in radians).
k.
dividend.
The remainder
(modulo n k)
divisor.
Figure 3.3
76
Some
for
example, 3.25, 0.05. Integers, written without decimal points, are exact
One should
numbers.
*,
exact numbers.
first
Our
strategy again
is
This
series,
first
that
procedure
is, it
sums
number of terms
summed, and the sum is
The
that illustrate
If
is
zero,
no terms are
(define harmonic-sun
(lambda (n)
(cond
((zero? n) 0)
...
To make
)))
we observe that we
get
(harmonic-sum n) from
(harmonic-sum n)
the
is
(+ (/
so
we complete the
Program
3.4
same
1
n)
as
definition with
harmonic-sum
(define harmonic-sum
(lambda (n)
(cond
((zero? n) 0)
(else (+ (/
n)
it is
is
and the smallest value of the numerical argument (in this caise, n is
Another simple illustration of this
3.2 Operations on
Numbers
77
idea
is
define
the construction of a
containing a specified
list
number
zeros. Its
code
We
contedning n
is
Progr2un 3.5
list
of zeros.
list-of-zeros
(define list-of-zeros
(laabda (n)
(cond
((zero? n)
'())
(else (cons
(length '(one))
(length '())
you
definitions of
will learn
are defined.
For example,
=^
=>
in the list.
list
(4 5 6)))
(2 3)
argument a
its
is
provided in
many
programming
When
you
test
all
Scheme because
name
it
is
good
We shall
implementations of Scheme.
Thus
for
enter your
definition.
To
define length,
length
is
zero,
we use
The base
recursion.
is
case
is
the
empty
lists.
list
We
whose
begin
(define length
(laabda (Is)
(if
(null? Is)
...
)))
Suppose we know (length (cdr Is)); then we get (length Is) by simply
adding one to (length (cdr Is)).
line of the definition:
78
last
Program
length
3.6
(define length
(lambda (Is)
(if (null? Is)
(addl
is
(list-ref '(a b
d e f) 3) ==> d
(list-ref '(a b
d e f) 0)
(list-ref '(a b c) 3)
=>
(list-ref '((1 2)
(list-ref '() 0)
=* Error: list-ref: Index
The number n
is
(list-ref Is n).
list
If
the index
index
0,
The
is
we use
the
cdr of the
list
list.
list
Is by
first
item
in the list
Is has
list,
shall successively
remove the
first
l)st
if
when
before or
We
list is
item
list
first
item
will not
If
in the list is
become empty
list-ref
we
item from
list is
from the
zero based.
in this recursion is
Thus we
()
is
strategy
first
is
Scheme procedure
as follows:
(define list-ref
(lambda (Is n)
(cond
(=
(length Is) n)
(error "list-ref: Index" n "out of range for list" Is))
((zero? n) (car Is))
(else (list-ref (cdr Is) (subl n))))))
3.2 Operations on
Numbers
79
on the
first call,
will
it
if it
remain
false in
call, since
program for list-ref the test for whether the length of Is is less
equal to n is made on each recursive call. However, if the test is false
In the
than or
to
We
desired item.
list
(define list-ref
(lambda (Is n)
(cond
(=
(length Is) n)
(define list-ref-helper
(lambda (Is n)
(if
(zero? n)
(car Is)
In general,
it is
definition of
is
list-ref,
is
recur-
as illustrated in this
rest of the
list is
it
calling the
can be written
80
dur-
list Is becomes empty while the index n is nonmust have been too large for the list. Thus the program
if,
as:
Progrcun 3.7
list-ref
(define list-ref
(lambda (Is n)
(cond
((null? Is)
Exercises
We
refer to
(3), and
of numbers as an n-iuple.
list
on n-tuples. In
all
may
use procedures
sum
Exercise 3.1:
sum
15
Exercise 3.2:
pairwise-sum
same
length,
ntpl-1 and ntpl-2, as arguments and produces a new n-tuple whose components are the sum of the corresponding components of ntpl-1 and ntpl-2.
Test your procedure on:
(pairwise-sum
'
(1 3 2)
(4 -1 2)) =* (5 2 4)
'()
'())
=>
(9.2 -1.0)
(18)
^*
S.2 Operations on
Numbers
81
dot-product
Exercise 3.3:
Define a procedure dot -product that takes two n-tuples of the same length,
multiplies the corresponding components,
resulting products.
This exercise can be done either directly or by using the procedures defined
in Exercises 3.1
and
3.2.
Exercise
mult-by-n
3.4-'
cedure on:
(mult-by-n 3
(1 2
(mult-by-n
(1 3
(mult-by-n -7 '())
'
3 4 5))
'
5 7 9
=>
==> (3 6 9 12 15)
11)
=> (000000)
()
index
Exercise 3.5:
If
the item
is
not in the
list,
is,
list
of
Test your
procedure on:
(index
(index
(index
(index
'(12345 6))=>2
'so
'a
'
'(do re me fa so la ti do))
-1
)
(b c d e)
'())=>
'cat
=^
=>
-1
make-list
Define a procedure make-list that takes as arguments a nonnegative
num and an item a and returns a list of num elements, each of which is
Exercise 3.6:
(meJce-list
=^ (no no no no no)
'maybe) ==* (maybe)
'no)
(make-list
'yes) ^^ ()
(length (make-list 7 'any)) ==* 7
(all-same? (make-list 100 'any))
8t
integer
a.
Test
count-background
Exercise 3.7:
of items
list
Is as arguments and returns the number of items in Is that are not equal?
to a. Test your procedure on:
list-front
Define a procedure list-front that takes as arguments a list of items Is and
a nonnegative integer num and returns the first num top-level items in Is. If
num is larger than the number of top-level items in Is, an error is signaled.
Exercise 3.8:
(list-front
'
(list-front
'
(a b c d e f g) 4)
=^ (abed)
^^
wrapa
Define a procedure wrapa that takes as arguments an item a and a nonnegative
integer num and wraps num sets of parentheses around the item a. Test your
Exercise 3.9:
procedure on:
(wrapa 'gift
1)
=>
(wrapa 'semdwich 2)
(gift)
^^
((sandwich))
=^*
(((((prisoner)))))
(wrapa 'prisoner 5)
(wrapa 'moon 0) ^^ moon
multiple?
Define a predicate multiple? that takes as arguments two integers ra and n
and returns #t if m is an integer multiple of n. (Hint: Use remainder.) Test
Exercise 3.10:
(multiple?
(multiple?
(multiple?
(multiple?
(multiple?
(multiple?
=> f
=^ #t
5 0) =* #f
20) => #t
17 1) => #t
0) => #t
7 2)
9 3)
3.2 Operations on
Numbers
83
sum-ol-odds
Exercise 3.11:
It
sum
of the
n odd numbers
first
is
equal to n^
For
example,
1
+ 3 + 5 + 7=
16
Exercise 3.12:
it
number
4^
n odd
first
n from
integers. Test
your
is
of terms.
n-tuple->integer
digits.
Exercise 3.13
Is
If
is
list
of length 1000,
how much
"cdring" in Is
is
necessary in each
of the three programs for list-ref presented in this section in order to find
is
most
efficient?
The numbers
operations of
and
* give
may
may
if
we
Let
is
not
i.
3)
It is
an exact arithmetic.
S = 1 + 3 + 5+
t-(2n-l). We get the szmie sum if we aAd the numbers in reverse
5 = (2n - 1) + (2n - 3) H
h 3 + 1. Adding the first terms of eeich sum, we get
order, so
Adding the second terms of each sima, we get 2n and in general adding corresponding
terms in the two svuns, we get the seune siun, 2n. There ese n such corresponding pairs of
terms, so 25 = n(2n) and S = v?
2n.
84
numerator, and
6,
which must be
composed of two
is
from
different
zero,
how
is its
integers: a
denominator.
the rational
number
or
fraction
is
represented.
is its
its
denominator. These
are called the two selector procedures for rational numbers, just as cslt
lists.
We
and
assume that we
shall also
We
call this
because
it
rational
its
number from
its parts.
Thus
for
is
rational
With
we proceed
to build
is
the
up the
We
rzero?, which
tests
number
is
is
equal to zero.
when
its
We
use
numerator
is
Program
rzero?
3.8
(define rzero?
(lambda (rtl)
(zero? (nuMr rtl))))
Now we
recall
how two
fractions are
{a*d)
(fe*c)
sum
b*d.
Thus
argument to maJte-ratl
to maike-ratl
is
is
if
in
85
Program
r+
3.9
(define r+
(laabda (x y)
(ake-ratl
(numr x) (denr y)) (* (n\ir y) (denr x)))
(+ (*
(*
(denr x)
(denr y)))))
is
a*c and denominator b*d, we can define the product procedure r* for rational
numbers
as follows:
Progreun 3.10
r*
(define r*
(lasbda (x y)
(eJce-ratl
(*
(nxoar x)
(numr y))
(*
(denr x)
(denr y)))))
Program
r-
defined by
is
r-
3.11
(define r-
(laabda (x y)
(ake-ratl
(-
(*
(*
(denr x)
(n\ir x)
(denr y))
(*
(denr y)))))
numbers
we can
86
are equal.
Two
is
numbers j and |
of r= given in Program
rational
are equal
3.14.
if
ad
6c.
Thus
Program
3.12
rinvert
(define rinvert
(lambda (rtl)
(if (rzero? rtl)
"
rtl)
Program
3.13
r/
(define r/
(laabda (x y)
(r* X (rinvert y))))
Progrm[i 3.14
r=
(define r
(laabda (x y)
( (
Program
(niiar x)
3.15
(denr y))
rpositive?
(define rpositive?
(laabda (rtl)
(or (and (positive? (niuu: rtl)) (positive? (denr rtl)))
We
number j is positive
Thus we get Program 3.15.
rational
The
if
a and
6 are
number x
is
than y
is
of r>.
Many
we can go on
numbers using
87
Program
3.16
r>
(define r>
(lambda (x y)
(rpositive? (r- x y))))
Program
(define
3.17
meix
BcLX
(lanbda (x y)
(if (> X y)
y)))
Program
3.18
(define
max
maix
(lanbda (x y)
(if (r> X y)
y)))
to this point.
its
two arguments, or
its
second
argument
how
the
The
if
important observation.
nnajc
When
We
are
is
obtained from
now
in
its
two
the definition
a position to
make an
definition
To demonstrate how
this
is
done,
let
pred
to stand for
Program
88
3.19.
Program
extreme-value
3.19
(lambda (pred X y)
(if (pred x y)
X
y)))
Now we
(define rmax
(lambda (x y)
(extreme-value r> x y)))
and
(define rmin
(leunbda (x y)
We
extreme- value,
(define
for if x
and y are
also be obtained
from
msix
(laimbda (x y)
and
for
min we have
(define min
(lambda (x y)
(extreme- Veil ue
The
< x
y)))
many
we
arguments
make use of it
when
we
talk
about
procedures
that
return other
7,
a better way of writing these definitions.
times. In Chapter
procedures,
We
is
shall see
can also define a procedure rprint that prints the results of our calcu-
form
as a fraction
89
Program
rprint
3.20
(define rprint
(lambda (rtl)
Thus
We
if
in
|,
dures numr and denr and the constructor procedure make-ratl without ever
r*, r-,
defined,
we can write
all
we simply
number. Thus
to use,
3,
if
user can
in
numbers
as abstract data.
We
are
we wish and
now
free to
have
choose any
What
We
how
we
and
choose.
is
that
power of abstraction.
we have been able to write all of our procedures, but we have not
been able to test them because we have not been given the constructor and
the selectors. We have reached the point where we choose a representation
So
far,
of the rational numbers and define the selector and constructor procedures.
rational
where b
is
For the
first
never to be zero.
90
We
as
Program
3.21
(define numr
(lambda (rtl)
(car rtl)))
(define denr
(lambda (rtl)
(cadr rtl)))
(define make-ratl
up our package
To
find the
tation,
It is
we have
make
to take the
list
list
represen-
efficient
and uses
less
storage space
if
are
(define numr
(lambda (rtl)
(car rtl)))
(define denr
(lambda (rtl)
(cdr rtl)))
is
(define make-ratl
(zero? int2)
(error "make-ratl: The denominator cannot be zero.")
(cons intl int2))))
91
is
We
do
knowl-
necessary to
so.
all
in
would have
no alterations.
in
We
and make-ratl,
ratl
is
selector procedures
would
still
be valid with
rest of the
(lists
make-
se-
rest of the
We
can then
specify concrete realizations of the data objects (or data structures) to run
is
data abstraction.
Exercises
Use the procedures defined
Exercise 3.14-
rminus
number
as its
argument and
Exercise 3.15:
same-sign?
(lambda (rtl)
Exercise 3.16:
is
correct.
rabs
92
number and
returns
its
absolute
make-ratl
Scheme has a procedure gcd that takes
Exercise 3.17:
their greatest
common
divisor, that
as
is,
(gcd 8 12)
=*
(gcd
5)
==^
(gcd 8 -12)
^^
4
^
list
1 is
(p q) in which p/q
the greatest
common
divisor of
p and
is
is
q)
and
in
which
q is positive. Test
= (4 5)
=> (-2 3)
=^ (-4 5)
8 -10)
-6 -9)
=^ (2 3)
=^
8)
(0 1)
(make-ratl 24 30)
(make-ratl -10 15)
(make-ratl
(make-ratl
(make-ratl
is
unique.
93
4.1
Overview
In this chapter,
lists.
Then we make
return table
is
top-level items in
We
discuss another
way of doing
structed.
The
compare the
factorial procedure
efficiency of various
methods
for
rates.
cdr of the
lists,
list.
lists.
The
is
first
list
list.
as aflat recursion,
procedure we define
is
We
the
the
flat procedure.
lists,
Scheme
list
that consists of the top-level items in Isl followed by the top-level items
in ls2.
We
say that we are appending ls2 to (the end of) Isl. For example,
(append '(a b c)
(append
We
()
'
'
'
(c d))
(a b c)
define
empty. Is2
is
(a b c c d)
(a b c)
is
returned.
in
first list.
which Isl
is
case:
(define append
(if
ls2
)))
...
absence of the
ls2
first top>-level
in
ls2)
differs
item
in Isl.
For example,
if
Isl
is
in the
(a b c) and
(d e), then (append (cdr Isl) ls2) gives us (b c d e). and only
is
the
is
same
as
Program
append
4.1
(define append
Is2
(cons
'car la 1)
(append (cdr
list
as its
argument
(reverse
'
list
l82)))))
the
list
(1 2 3 4 5)
=*
(5 4 3 2 1)
96
is
Issi)
=^
((5 6)
(3 4)
(1 2))
We
again use recursion and look at what reverse does to the cdr of the
(reverse
To
get
reverse of
into a
list
(5 4 3 2)
(1 2 3 4 5)
the
=^
(2 3 4 5))
'
list
example above,
We
from (5 4 3
can do this
2),
is
We
empty list as the base case and note that if we reverse the
the empty list, we still have the empty list. Thus we can begin the
take the
items in
the
empty
if
the
list is
empty,
returned.
list is
(define reverse
(lambda (Is)
(null? Is)
(if
'()
...
To
that
get
is
)))
Program
4.2
We
list
that
is
list
the
reverse
(define reverse
(leunbda (Is)
list
number
is less
if
each
in the
list.
is
it
we have two
now
list
if
the
list
given above
is
list
in
list
in increasing order.
97
the
list
lists
list.
If either
of the two
lists.
Program
4.3
merge
rest
(define merge
We
shall use
The
merge
definition of
earlier. It
in
))
))
lists.
first,
present
predecessor
its definition.
is
which
is
Program
it
4.4
even?
(lambda (int)
(zero'? int)
ft
98
illustrates
We
if its
how each
of two procedures
predecessor
successively by
is
1
even.
) ) ) )
is
even
if
(define even?
(if
it
it
to
and
Program
odd?
4.5
(define odd?
(lanbda (int)
(if (zero? int)
mutual recursion
in
is
This
called.
called,
is
is
and
in
an example of
of items.
list
all top-level
is
now we continue
it is
true, the
empty
list is
list
Is.
As
all
top-level
define a procedure
top-level occurrences of
now
Let us
first
Is.
(cond
((null? Is)
...
'())
)))
Next,
if
Is
is
first
write a
99
You could
list.
Program
4.6
remove
(define reaove
(lambda (it en
Is
(cond
((null? Is)
'())
a version
(ceir Is)
named remv
flat
first
The
exercises
Exercises
Exercise
4'^-'
insert-left
Define a procedure insert-left with parameters new, old, and Is that builds
a
list
list
left
^(001001)
Exercise 4-^'
insert -right
list
list
Exercise 4-3:
subst
Define a procedure subst with parameters new, old. and Is that builds a
100
list
list
Is
'(abaca)) =>
1
D) =^ (0
(z b z c z)
'(0
0)
=^
deepen-l
Exercise 4-4'
Define a procedure deepen-1 with parameter Is that wraps a pair of parentheses around each top-level item in Is. Test your procedure on:
(deepen-1
'(abed)) =>
((a)
(b)
(deepen-1
4.3
'())
=>
(d))
(c)
=>
(((a b))
((c (d e)))
(f))
()
Deep Recursion
In this section,
is
nested in the
list
all
(a (b c)).
the sublists of a
0.
is.
If
It is
list.
We
say
convenient to have
an item
is
not enclosed by
nesting level
objects in the
We
(a (b c)
list
(count-all '((a b) c
2.
(count-all '(()
3.
(count-all '((())))
(count-all '()) =*
((d (e)))))
()))
=>
that
a,
1.
4.
(d (e f ))) are
define a procedure
items in the
To
list
is
not a
=^
we use the
=>
lists
list is
list
were counted,
lists
lists.
101
The base
returns zero.
Thus the
is
the
empty
count-all
(define count-all
(lambda (Is)
(cond
((null? Is) 0)
...
If
Is
is
how we can
diff'er
)))
get
in (ceu: Is).
is
If
(car Is)
is
atomic,
definition with:
(define count-all
(lambda (Is)
(cond
((null? Is) 0)
((not (pair? (car Is))) (addl (count-all (cdr Is))))
)))
...
When
(car Is)
is
a pair (as
is
amount
and
3),
we must count
all (cdr Is)) to get the value of (count-all Is). Thus we complete the
definition with:
Program
count-all
4.7
(define count-all
(lambda (Is)
(cond
((null? Is) 0)
((not (pair? (car Is))) (addl (count-all (cdr Is))))
In fact,
follows:
102
last
if
we write the
definition as
(define count-all
(leunbda (Is)
(cond
((null? Is) 0)
(else (+ (if (pair? (car Is))
The
list is
list.
list
car of the
a pair, we apply the procedure being defined both to the car and to the
cdr of the
list,
when the
When
list.
the recursion
is
over
list,
we
call it
all
is
a deep recursion.
procedure defined
it
have avoided the use of the not in the second cond clause by changing the
order in which we considered the last two cases.
definition:
(define count-all
(lambda (Is)
(cond
((null? Is) 0)
((pair? (car Is))
(+ (count-all (car Is))
(else (+
Many
of the flat procedures defined earlier have analogs that are deep pro-
To
illustrate this,
=>
((b (c))
(b (c)))
The base
case
is
the
empty
list,
list
is
103
(define remove-all
((null? Is)
...
We
'())
)))
(cdr Is)).
item Is)
is
If
the
same
as
(define remove-all
(Icifflbda
(item Is)
(cond
If
(cax Is)
)))
is
a pair that
is
all
occur-
rences of item from (car Is) and cons the result onto (remove-all item
((null? Is)
'())
Is))
(ccir
Finally,
if
(ceir
Is))
)))
(car Is)
is
atomic and
is
in order to get
(remove-all item
We
(define remove-all
(leimbda (item Is)
(cond
((null? Is)
((equal?
'())
(cur Is)
(ceir
Is))
104
it
last
two
Program
4.8
remove-all
(define remove-all
(laj&bda (item Is)
(cond
((null? Is)
'())
we again see that when (car Is) is a pair not equal to item,
the procedure remove-all is applied recursively to both the car and the
cdr of Is. Thus remove-all displays this characteristic behavior of deeply
In this example,
recursive procedures.
We
If
is
bound
Program
4.9
remq-all
(define remq-all
(leifflbda
(symbl
Isi)
(cond
((null? Is)
())
Ifi)
When
the
flat
procedure reverse
is
applied to a
list,
we
get a
new
list
with
We
=>
((d (e f)) (b c) a)
can also define a procedure reverse-all that not only reverses the order
105
list
(reverse-all
'
empty
list.
Thus the
(d (e f ))))=* (((f e) d)
(a (b c)
We
list is
(c b) a)
(define reverse-zdl
(lambda (Is)
(cond
((null? Is)
To
'())
)))
...
(cdr Is)).
(car Is).
If
(cax Is)
is
We
its
(define reverse-all
(lambda (Is)
(cond
((null? Is)
((pair?
(ceur
'())
Is))
(cau:
Is)))))
)))
is
(lambda (Is)
(cond
((null? Is)
'())
(else
106
it
at the
recursion.
in the
We
second
cond clause.
It is
the similarity between the two alternatives that begin with append in the
last
They
differ
Program
reverse-all
4.10
(define reverse-all
(lambda (Is)
(if
(null? Is)
'0
(append (reverse- all (cdr Is))
(list (if (pair? (car Is))
In this section,
These have the characteristic property that a recursive step applies the procedure being defined to both the car and the cdr of the
list.
Exercises
subst-all, substq-all
Exercise 4-5:
Define a procedure subst-all with call structure (subst-all new old Is)
that replaces each occurrence of the item old in a
list
(subst-all
'z
'a
=>
(subst-all
'(1)
(a (d a))))
'(a (b (a c))
'(((1)
(z
(0))))
(b
=>
(z c))
((0
(z
(d z)))
(0)))
=>
Also define a procedure substq-all in which the parameters new and old are
only bound to symbols, so that eq? can be used for the sameness
test.
107
insert-left-all
Define a procedure insert-left-all with call structure (insert-left-all
new old Is) that inserts the item new to the left of each occurrence of the
item old in the list Is. Test your procedure on:
Exercise 4-6:
(insert-left-all
'a
'z
'(a
(b a)
=>
(insert-left-all
(insert-left-all
((a (c))))))
((b z a)
(z a
'a
'z
'a '())
=^
sum-all
Exercise 4-7:
may
((z a (c)))))
'z
sum
of the
numbers
in a list that
(sum-all '((1 3)
(5 7)
11)))
(9
(sum-all '())
=> 36
=> 25
=>
There
its
is
way
a convenient
of thinking of a
list
The
a node that
is
to the root
subtree,
Each item
itself
original
list
and the
tree
list is
forms a
((e f) g)
(a (b c d)
list
list is
is
a node of this
tree.
Each
sublist
is
An
branch
is
is
nested in the
list
by looking at
We
is
We
its
list is
at nesting level
is
the
and the
For example,
maximum of the
nesting levels of
all
its
lowest leaves.
To traverse a tree, that is, to move down the tree from one node to another,
we use the procedures cau: and cdr. Taking the car of a list corresponds to
108
(a (b c d)
((e f) g))
((e f) g)
Figure 4.11
list
(a (b c d)
((e f) g))
((e f) g)
Figure 4.12
f) g)
tree.
list
is
left
is
reached
using caaddr.
We
its
define a procedure
depth.
be either atomic or a
as its
list.
item
is
atomic, we
109
Program
depth
4.13
(define depth
(lambda (item)
(if (not (pair? item))
assign
it
depth
0.
Since the
empty
list is
atomic,
it
We
We
take
(pair? item)),
as the base case for the recursive definition the test (not
for
depth with:
(define depth
(lambda (item)
(not (pair? item))
(if
)))
...
The depth
is
is
Taking the
its
leftmost branch
moves
one greater than the depth of (car item). The depth of the
of the branches
is
rest
Program 4.13.
The procedure depth gives
displayed in
us the
maximum number
of levels in a tree
argument.
We
list
representing
of
its sublist
its
to be at top level.
We
call this
list
of
is
raised out
procedure flatten.
When we
apply
list,
it
to the
list
(a (b c d)
itself.
definition of
flatten with:
(define flatten
(leunbda (Is)
(cond
((null? Is)
...
When
by
110
first
Is
is
'())
)))
is
a pair.
If it is,
we
flatten
(car Is)
to
to get
it
(flatten
(define flatten
(lEunbda (Is)
(cond
((null? Is)
'())
...
(car Is)
is
atomic, so we cons
it
onto (flatten
Program
flatten
4.14
(define flatten
(lambda (Is)
(cond
((null? Is)
'())
We
have discussed
top-level items of a
]-s)
and deep
flat
This
list.
is
recursion.
flat
recursion
the corresponding tree, which are one level below the root.
is
over
all
This
list.
is
over the
That
deep recursion
is
is
why deep
recursion
is
also referred
to as tree recursion.
We
item from a
list.
Let us
list
name
first
the procedure
at a couple of
examples.
1.
(remove-leftmost
'b
'(a (b c)
(c
=>
2.
(remove-leftmost
'
(c d)
(b a))))
(a (c)
(c
(b a)))
((c d)
e)))
(e))
'((a (b c))
111
Example
In
1,
the
that occurs in (c
first
(b a)
is
in (b
not removed.
c)
We
is
list
is
b that occurs
list is
returned.
terminating condition:
(define remove-leftmost
((null? Is)
...
'())
)))
is
the
(define remove-leftmost
((null? Is)
'())
(car Is)
If
)))
is
atomic and
is
list
cis
is
obtained
get:
(define remove-leftmost
((null? Is)
'())
...
We
item.
still
If
in
is
nonempty
list
not equal to
at
we
see that
we
get a
112
list
with the
first
item
in Is.
We
want to
Program
4.15
remove-leftmost
(define remove-leftmost
((null? Is)
'())
Program
4.16
(cdr Is)))
member-all?
(define member-all?
#f
first
its first
occurrence
may
we must
first
(car Is).
We
first
occurrence of item in Is
is
in
we
If
item
is
in
(car Is), we
cons (remove-leftmost item (car Is)) onto (cdr Is) to get the answer.
Otherwise, we cons (car Is) onto (remove-leftmost item (cdr Is)) to
The
definition
4.15.
the third cond clause and the alternative in the else clause are the same.
The new
version
is
tests
We
we make.
113
Program
remove-leftmost
4.17
(define remove-leftmost
((null? Is)
'())
The
list
remove-leftmost
we have
to test
car of the
list
twice in
remove-leftmost
this
double cdring.
in
some
cases.
Chapter
We
(cdr Is)))
5,
We
differs
whether item
is
from the
list re-
where a definition
is
flat
and deep
(tree) recursions.
Exercises
Exercise 4-8:
count -parens-all
list
as its
argument and counts the number of opening and closing parentheses in the
list.
(count-parens-all '()) ^^ 2
(count -parens -all '((a b) c)) ^^ 4
(count-parens-all '(((a () b) c) () ((d) e)))
Exercise 4-9:
14
count -background-all
and a
list
as item.
its
Is and returns the number of items in Is that are not the same
for the
114
arguments item
=>
data shown
in the
Program
4.18
fact
(define fact
(lambda (n)
(if (zero? n)
1
(*
Exercise 4-10:
leftmost
nonempty
list.
list
as
its
argument and
Exercise 4-1 1-
rightmost
nonempty
list.
list
4.5
as
its
argument and
We
examples
a nonnegative integer n
the
We
in this section.
number multiplied
cis
its
consider several
its factorial
that
is,
5x4x3x2x1
much
same kind
120.
We
we used with
lists, but instead of using cdr to reduce the size of the argument, we use subl.
Eventually the successive applications of subl to the argument will reduce it
derive this procedure using
We
to
0.
1.
The
the
of reasoning as
is
all
To
get (fact n)
by
n.
From
we
1,
so that (fact 0)
is
n.
this,
is
fact
we have
in
to
Program
do
is
multiply
it
4.18.
115
When
much
is
3,
a return table
same as the one that was built for the procedure swapper
in Chapter 2. The value of (fact 3) is denoted by answer-1. It is 3 times
(fact 2) so the evaluation of answer-1 must wait until answer-2 is evaluated,
where answer-2 is (fact 2). Thus the first two rows of the return table are:
is
built
the
answer-1
answer-2
When we
is
is
When we
where (fact 0)
way up the
it
answer-2)
answer-3)
is
(* 3
is
(*
is
(fact
1)
for
answer-2)
(fact 2)
(* 3
is 1.
Now
that
in the
answer-2)
answer-3)
answer-^)
is
(* 3
is
(* 2
is
(*
is
(fact 0)
is 1,
we work our
is
known
gives us:
answer-4
answer-3
answer- 2
answer- 1
so (fact 3)
is 6.
"
is
is
is
In finding (fact 3), the return table has four rows. In the
on the
left
terminating condition of the program. Then each of the other three variables
on the right was computed with a multiplication, so there were three multiplications required to complete the computation of (fact 3).
The building
116
(fiact
(* 3
3)
(fad 2))
;
(fact 1)))
(* 1 (fact 0))))
(* 3 (* 2 (* 1 1)))
(* 3
(* 2
(* 3
(*
(* 3
(*
D)
(* 3 2)
on the right
terminating condition
a multiplication
We
is
found to be
n+
table has
rows. In the
n rows
right,
making a
total of
becomes
would be n
n, there
is
n multiplications
is
number
is
when we compute
constructed
procedure fact.
When
the fac-
a return table and backward substitution to get the answer, we say that the
computation
is
defining a procedure to
a return table.
compute the
We now
factorial of a
returned.
In general,
when
is
true, the
for other
answer
is
needed values,
already computed
We
computational process
called
is
an
like the
is
not neces-
iterative process.
On
build
way of
and
look at another
we saw
is
call.
is
an
The
calls.
In
table
is
is
needed.
117
which
is
teger, called
how
ace
1,
works
in
computing the
to
1.
and aec
When
are computing,
On
replaced by
is
factorial of 3.
Initially,
its
The
is
second column
is
is
bound
is
in-
Here
step.
to 3
is
and
reduced by
row.
true,
aee
is
bound
it
is
we
6.
This
is
row.
aee
6
6
To
define fact-it,
(zero? n)
for
which n
true, the
is
we begin the
is
is
zero.
returned.
When
Thus
definition with:
(define fact-it
(lanbda (n ace)
(if
(zero? n)
ace
...
If
is
)))
not zero, we
call
Program
4.19
is
completed with:
fact-it
(lambda (n ace)
(if (zero? n)
ace
an invocation (fact-it 3
turned:
118
and
is re-
(fact-it 3 1)
(fact-it 2 3)
(fact-it 1 6)
(fact-it
6)
6
up waiting
uncomputed values
to be returned. The accumulator is bound to the answer when the terminating
condition is true, and the answer is returned without any backward substitution. The fact that there is no waiting operation on each recursive invocation
of fact-it is seen when we look at the last line of the definition. After the
procedure call, there is no further operation to be done. Compare this last
line
with the
must
built
still
We
be multiplied by
n.
When fact-it
for
last line,
(*
result
is
When we
is
fact
called,
is
called, the
no additional
as an iterative
we
see
that the computation does not build up a return table of operations waiting
for values to be returned.
If we count the number of times we call the procedure fact-it and the
number of multiplications, we see that the total number of multiplications
is the same for the procedures fact-it and fact.
However, the backward
substitution in the return table, which is built up when evaluating fact,
requires more memory space than is needed when evaluating the iterative
fact-it, which needs no return table. In the next section, we look at another
more dramatic.
To compute the
is
(define fact
(lambda (n)
(fact-it n 1)))
119
Exercises
Exercise 4-i2
Enter the procedure fact into the computer and compute (fact n) for n =
You
will
Exercise 4-i3
harmonic-suin-it
sums the
first
n terms
1111
summing
11
23
where logn
is
It
,11
n -
n-1
The
23
Algorithm
"filius
his
nickname,
are
in a year? It
produces another pair and that rabbits begin to bear young two months after
own birth.
The sequence of numbers that give
month is 1, 2, 3, 5, 8, 13, 21, 34, 55,
their
at the
two
first
the
number
pair
had a pair of
This
tells
offsprings, so
us that
we have
At the end of two months, only one pair is old enough to have
offsprings, so we have three pairs. At the end of three months, the first pair
of offsprings is old enough to bear young, so this time we get two new pairs,
120
pairs.
and we have
is
We now
define a procedure
If
number.
>
1,
(fib 1)
is 0,
(fib n)
is
is
1,
sum
the
(fib 2)
is
of (fib (-
1,
(fib 3)
is 2,
and
(-
Program
We
its
have
in general, for
n.
2)).
We now
Program
4.20.
fib
4.20
(define fib
(lambda (n)
(if
n 2)
n
(fib (- n
(+
D)
(fib (- n 2))))))
(fib 4)
(fib 3)
(fib 2)
To
trace
(fib 1)
(fib 1)
(fib 0)
(fib 0)
(fib 1)
Figure 4.21
(fib 2)
how (fib
4)
is
evaluated,
we make a
which
121
the root
is
is
the other to a node (lib 2). Each of these gives rise to two branches, (lib
3) giving
rise to
and
0, respectively.
This tree
This continues
is
tree
because each
is not a leaf has at most two branches going down from it.
From Figure 4.21, we see that each node corresponds to a procedure call that
made in evaluating (lib 4). In this case, there are nine procedure calls.
node that
is
Each branch point (a node from which two branches originate) corresponds
we can build a
trees for
we
calls
will
have
fifteen
(lib 5) and
calls
We suggest
that you
for
and additions.
It is
not
difficult
to see from the trees that if (calls-lib n) tells how many procedure calls
there are in computing (lib n) and (adds -lib n) tells how many additions
there are in computing (lib n), then these procedures satisfy the relations
(calls-lib 0)
(calls-fib 1)
la
is
(calls-fib n)
is
and
(adds-f ib 0)
is
(adds-fib
1)
ts
(adds-f ib n)
ts
We
012345678
n
(fib n)
(calls-fib n)
(adds-fib n)
Table 4.22
The number
122
34 55
8 13 21
9 15 25 41 67 109 177
3
1
calls
call,
12 20 33
54
88
and additions
10
Count of procedure
number
lib
of additions increase so
This leads to
accl
acc2
1
Table 4.23
13
Accumulator values
same fib
is
of times, so that the different recursive calls repeat each other's work. In the
tree
shown
in
We next
three times.
is
look at an iterative
method
for
is
invoked
numbers.
how
clue to
numbers
is
to set
up an
We
in accumulators,
it
in the sequence.
which we
call
Thus we have
first
to store
numbers to
two jiumbers
and
start,
acc2
accl
At each
step,
accl holds the current Fibonacci number and acc2 holds the
next one. Thus we can describe the algorithm that takes us from one step to
the next as follows:
1.
The new
value of accl
2.
The new
We
is
is
the
same
the
sum
and acc2.
apply these rules to extend the table to show the next six steps, as
dis-
to define a procedure
and the two accumulators, accl and acc2, and returns the Fibonacci number corresponding to n. There are two ways that we
can use the algorithm given to write the code. In the first method, we can
a nonnegative integer
n,
use the value stored in accl (initially 0) to give us the answer. In that case,
one iteration of the algorithm gives us (fib 1), two iterations give us (fib
2), and in general n iterations give us (fib n) for any positive n. In the
123
Program
fib-it
4.24
(define fib-it
acc2
(fib-it (subl n) acc2 (+ accl acc2)))))
(initially l) to give us
the answer. In this case, one iteration of the algorithm gives us (fib 2), two
iterations give us (fib 3),
is
more
and
(n
in general,
1) iterations give
us (fib n).
We
opt
Our iterative procedure fib-it takes three parameters: the positive integer
n and the two accumulators accl and acc2. To implement the algorithm
stated above, we successively replace acc2 by the sum of accl and acc2,
and replace accl by the previous value of acc2. Then to compute the nth
Fibonacci number, we must repeat the process (n 1) times. We use the
variable n as a counter and reduce it by one on each pass. When n reaches 1,
the accumulator acc2 contains the answer. This leads to the definition given
in
Program
Let's
4.24.
1) to see
how
this works.
On
successive
passes through the program, the following procedure calls are made:
(fib-it
(fib-it
(fib-it
(fib-it
(fib-it
(fib-it
1)
1)
2)
3 2 3)
2 3 5)
1
5 8)
and the answer is the final value of acc2, which is 8. To compute the sixth
Fibonacci number, we only make six procedure calls and 5 additions. In
general, to compute the nth Fibonacci number, we make n procedure calls
and do n
additions.
of procedure calls
This
is
is
invoked.
The
iterative version,
fib- it, is certainly more efficient and saves a considerable amount of time
in computing the Fibonacci numbers. The ordinary recursive version, fib, is
less efficient
in
124
but
it
Again,
in
if
(define fib
(lambda (n)
(zero? n)
(if
(fib-it n
We
1))))
may
take
algorithms
is
to
be (res n). In our discussion, fib depended on the argument n, and we can
define as the resources used the
sum
Inspection of the table for (calls-fib n) shows that the following relation
exists
(calls-fib n)
Similarly,
(adds-fib n)
so that
(res n)
We now
If
you
prefer,
F{n
F[n)
1)
if
a procedure
+ F{n -
(fib n)
2)
satisfies the
and the
for all n.
F(0)
formula
for
and F{1)
1,
then
some number a
use the
initial conditions
We begin
We
we
We then look
are lucky
enough to find
finding a
^n
a
==
n 1
a
+ an2
I
125
=0 +
a^
(l
v/5)
(l-v/5)
'=
that since both a" and 6" satisfy the Fibonacci recurrence
same recurrence
and
so that F(0)
relation.
and F(l)
1.
We
= Aa" + 56"
The constants
and B
will
now be
F(l)
We
find that
A -B =
=
=
for n
=A+5
= .4a + 56
and n
all n.
1,
and B, F{n)
satisfy
and we have
Thus (lib n)
is
somewhat
less
is
somewhat
less
than
3(1.7").
In general,
function / of n
if
there
is
a constant
is
some
sufficiently large.
1)
is
2n
1,
In our case,
which
is
n.
We say
that in this
(res n) has linear order. Thus the time required to compute (lib n)
126
is
n,
Program
reverse-it
4.25
(define reverse-it
ace
We
(cEir Is)
ace)))))
makes.
list
We
We now
(define reverse
(lambda (Is)
(reverse-it Is '())))
We
leave
it
as an exercise to
compare
still
is
version with a
the answer
when Is
is
tution in a return table to get the answer. Furthermore the iterative version
does not use the helping procedure append. Generally, iterative versions tend
to require
more arguments.
Exercises
Exercise 4-15
Rewrite the recursive version of the procedure fib with the
(writeln "n =
"
line
n)
Then compute (fib 4) and compare the results with the tree in Figure 4.21. Also compute (fib 5) and (fib
6) and observe how the number of recursive calls to fib increases.
inserted just below the line (Isimbda (n).
127
Exercise 4- 16
Rewrite the iterative version of the procedure fib-it with the line
(writeln "n =
"
accl =
",
"
"
acc2)
Compute (fib-it 4
4) in
6
1)
1).
to get
an idea of
in
Also
their
rates of growth.
length-it
Write an iterative version length-it of the procedure length, that computes
Exercise 4-18:
the length of a
list.
mk-asc-list-of-ints, mk-desc-list-of-ints
Exercise 4-19:
produces a
iterative
list
n,
list
to
Exercise 4-20:
occurs, occurs-it
Define both recursive and iterative versions of a procedure occurs that counts
the
number
version occurs-it.
level in
(a b a c a d)
(b c a (b a) c a)
(b (c d))
128
lists:
list.
the
5.1
Overview
When we
bind a variable to some value using define, we are able to use that
it is
5.2 Let
and Letrec
You may have wondered how Scheme knows what
to procedures) like +,
catx,
definitions are
kept in a table which we call the initial global environment. This initial global
environment
is
is
in place
When
its
a given variable
environment to see
to use
define
val.
The
We
expression (define
we
we
call
the user
ments)
is
scanned to see
if
that variable
is
The
is
bound
to a value.
If
is
a binding
unbound
in
lambda
lambda expression
(lambda (x y) (+ x y))
the variables x and y occurring in the body (+ x y) of the
lambda expression
are locally bound (or lambda bound) in the expression (+ x y) since the x and
y occur in the
list
procedure, which
and
3,
as in
(danbda
(+ x y)) 2 3)
(x y)
we can think
is
of a
new
table being
bound
of parameters of that
is
to 2
y gives (+
call.
bound
x y) the value 5, and
and y
is
locally
made,
to 3.
Then
is
which
locally
((lambda (x y) (+ x y)) 2 3)
5.
variable occurring in a
that expression
(lambda
is
(f y)
(f a (f y z)))
a and z are
130
lambda bound
When
in the expression,
the application
((lambda
(f y)
(f
a (f y z))) cons 3)
is
ands are
first
evaluated.
When
is
the
the lambda expression) and its two operlambda expression is evaluated, bindings
are found for the free variables in a nonlocal environment. Then, with these
bindings for the free variables, the body of the lambda expression
If either
3.
message to that
hand,
if
is
effect
bound
to
is
is
and z
is
evaluated
bound
to
is
bound
made.
is
On
the other
We
we
body of a lambda
expression.
local
environment
lambda
for another
in the global
This
expression.
environment or
is
illustrated
in a
by the
following example:
((lambda (x)
((lambda (y)
(- X y))
15))
20)
expression, but
environment
lambda
expression.
lambda
expression,
The
variable x
binding
The
is
free in the
is
found
in the local
its
is 5.
In the example
(lambda (x y) (+ x y))
for the
moment
be
in the scope of
a variable x
if
that expression
list
is
in the
body of a lambda
of parameters.
tell
is
scoped.
5.2 Let
Scheme
is
and Letrec
such a language.
ISl
Scheme provides several other ways of making these local bindings for variables, although we shall later see that these are all ultimately related to
lambda bindings. The two that we discuss here are let expressions and letrec expressions. To bind the variable var to the value of an expression val
in the expression body, we use a let expression (which is a special form with
keyword let) with the syntax:
The scope
the
(var2 va/2)
is
to
we write
vaVn
is
let
(let ((a 2)
(b 3))
(+ a b))
bound to 2 and b
evaluated. Another example is
returns
is
5.
Here a
(let ((a +)
is
is
bound
to 3
when
the
body
(+ a b)
(b 3))
(a 2 b))
returns
to
3.
5,
since a
is
bound
and b
is
bound
is
bound
The
argument by
2,
0.2.
local binding always takes precedence over the global or other nonlocal
132
[1]
(define a 5)
[2]
(addl a)
[5]
(begin
[3]
(addl a))
(addl a)))
(addl a)
[4]
4
6
The define
(addl a)
In [3]
in [2]
is
its
locally
value
bound
is
found
to 3,
in the global
is
is
bound
is
When
let
is
encountered in
environment and 6
The scope
is
is
returned.
evaluated with
expression.
Thus
in
[4]
the value of
version of the
expression
5.
same computation
in
is 6.
In [5],
we
see a
but here the local binding takes precedence over the nonlocal bindings.
We
(let ((a 2)
meaning of the
let
expression
(b 3))
(+ab))
when we
realize that
it is
equivalent to an application of a
lambda
expression:
((lambda (a b) (+ a b)) 2 3)
To
first
environment to get
5.
is
ivar2 ^0/2)
...
From
this representation,
5.2 Let
let's
.,
we
vain
...
lambda
expression:
see that
is
any
...
free variable
vain)
appearing in the
For
consider
and Letrec
133
[1]
(define a 10)
[2]
(define b 2)
[3]
[4]
(b 2))
30
a b))
30
bound globally
The
to 2 in [2]. Then
variable a is free in the expression (+ a 5), so the value to which a is bound
must be looked up in the nonlocal (here global) environment. There we find
that a is bound to 10, so (+ a 5) is 15. The next step is to make a local
environment where a is bound to 15. We are now ready to evaluate the body
of the let expression (* a b). We first try to look up the values of a and b
in the local environment. We find that a is locally bound to 15, but b is not
In this example, a
is
bound
globally to 10 in Cl],
and b
is first
is
evaluated.^
We
found there.
the free variables are looked up in a nonlocal but not global environment.
let
expressions,
we
see
how
expression, for
is
if
we do not do
so,
we might be
in evaluating
an
an interesting example:
[1]
(define addb
(let ((b 100))
(Icunbda (x)
(+ X b))))
[2]
(addb 25))
125
Because b
is
bound
to 10 in [2]
is
the
body of the
expres-
The symbol +
let
is
bound
to
is also free in (+ a 5 ) and its value is found in the initid global environment
be the addition operator. The number 5 eveduates to itself. Simileirly, the symbol is free
in the body, eind its value is found in the initial globed environment to be the multiplication
^
to
operator.
134
100. This
when
is
it is
is
is
is
used
125.
Let's look at [1] again. The variable addb is bound to the value of the
lambda expression, thereby defining addb to be a procedure. The value of
this lambda expression must keep track of three things as it "waits" to be
list
expression, which
free variable
in
which b
is
is
is
of parameters, which
bound, which
bound
to 100.
list
is
The
value of a
lambda expression
let
is
expression
a procedure
is
lambda expression
is
In
body of the lambda expression, and (3) the environment in which the
body are bound at the time the lambda expression is
evaluated. When the procedure is applied, its parameters are bound to its
arguments, and the body is evaluated, with the free variables looked up in
the environment stored in the closure. Thus in [2], (addb 25) produces the
value 125 because the addb is bound to the procedure in which b is bound to
the
100.
let
expressions:
(+ x b)))
(b 0.5))
(/
The
b (add2 b))))
first let
we
call
Environment
(Figure 5.1).
m
Figure 5.1
Environment
we call
Environment 2. The first entry in this environment is add2, which is bound
to the value of (lambda (x) (+ x b)). The x in (+ x b) is lambda bound
in that lambda expression, and the value of b can be found in Environment 1.
The
inner
let
1S5
expression
let
is
in effect
1 is 2.
and we
first
expression, so
let
Procedure
add2
body of the
in the
is
Environment
(+ I b)
(x)
2 (Figure 5.2).
0.5
Environment
Figure 5.2
bound
We
was
x) or are
now ready
are
bound
are either
bound outside
of the let
which add2
We
let
is
or
first,
is
lambda
finding that b
is
bound
to 0.5.
Thus
is
Program
as the
list
of item.
If
4.15.
Is except that
(car Is)
is
it
when Is
is
(cdr Is).
is
(car Is)
to produce a
it
is
list
the
same
either
is
is
the
empty
list.
If
is
a pair, or
it
is
is
not a pair.
If it is
two
a pair,
But
if
we use
this
(cdr Is))
when making
the test
136
(remove-leftmost item
Program
5.3
(cju:
Is))
this expression
is
needed.
Here
is
remove-leftmost
(define remove-leftmost
((equal?
(ceir Is)
rem-list)
(else (cons
In a
let
(ecu:
'.
Ls)
expression
(*
(fact 4))
will return
is
this
code
to become familiar with the messages that your system returns. This message
refers to the
5.2 Let
fact occurring
and Letrec
in the
lambda expression
137
which
is
the problem of
We
unbound
variables that
recursion
is
for
(letrec
letrec
is
the
vali)
((.vari
same
(vor2 ^0^3)
va/2
vain
and
expressions vali
uori, var2,
.,
make
to avoid
above example.
form with
when
val2,
in the
to use a
desired.
The syntax
variables.
if
expression to
let
we want
expression, we have
we encountered
by using a
Thus
expression. ^
let
The scope
(.varn
vain)) body)
.
.
(*
(fact 4))
We
ample
can also have mutual recursion in a letrec expression, as the next exillustrates:
Program
5.4
we call (fact 0), the value 1 is returned, since the consequent of the if expression is
and the alternative, in which the call to fact is made, is not evaluated. In this case
no error message would result.
If
true
138
Program
fact
5.4
(define fact
(lambda (n)
(letrec ((fact-it
(lambda (k ace)
(if (zero? k)
ace
(fact-it n 1))))
Program
swapper
5.5
(define swapper
(lambda (x y Is)
(letrec
((swap
(lambda (Is*)
(eond
((null? Is*)
'())
:ar Is*)
(<
(swap Is))))
is
The
name
for
name
something
clashes.
else earlier
Program 2.8, which has three parameters, x, y, and Is, where x and y are
items and Is is a list. Then (swapper x y Is) produces a new list in which
x's and y's are interchanged. Note that in Program 2.8 each time we invoked
swapper recursively, we had to rewrite the variables x and y. We can avoid
this rewriting if we use letrec to define a local procedure, say swap, which
takes only one formal argument, say Is*, and rewrite the definition of the
5.2 Let
and
Letrec
5.5.
139
The parameter
swap
is
bound
swap
to
called in the
in the outer
leist
when the
Is*, and
is
lambda
expression.
We
argument
Is,
is
which
is
lambda
Is instead of Is* as the parameter in swap since the lexical scoping specifies
When we
is
in effect.
In this section,
call
We
more
efficient
and
easier
to understand.
Exercises
Exercise 5.1
Find the value of each of the following expressions, writing the local environ-
ments
is
it
bound
in
a lambda or
let
(max x a))))
((a 1)
(let
((b 3)
(b 2))
(c
(+ a b)))
Exercise 5.2
Find the value of each of the following
a.
140
letrec expressions:
(letrec
((loop
(lambda (n k)
(cond
((zero? k) n)
( n k) (loop k n))
(else (loop k (remainder n k) ))))))
(loop 9 12))
variable
expression.
it is
bound.
Also
b.
(letrec
((loop
(n)
(leifflbda
(if
(zero? n)
(+ (remainder n 10)
(loop 1234))
Exercise 5.3
Write the two expressions
in Parts a
let
and b of Exercise
5.1 as nested
lambda
expressions.
Exercise 5.4
Find the value of the following
letrec expression.
(letrec ((mystery
(lambda (tuple odds evens)
(if (null? tuple)
(append odds evens)
(let ((next-int (car tuple)))
(if (odd? next-int)
(mystery (cdr tuple)
(cons next-int odds) evens)
(mystery (cdr tuple)
odds (cons next-int evens))))))))
(mystery
'
(3 16 4 7 9 12 24)
'
'
()))
Exercise 5.5
We
define a procedure
mystery
as follows:
(define mystery
(leUDbda (n)
(letrec
(
(mystery-helper
(lambda (n s)
(cond
(append
s))
1
s) )))))))
(mystery-helper n '()))))
What
is
returned
when mystery
5.2 Let
is
and Letrec
when (mystery 4)
is
is
returned
141
insert-left-all
Exercise 5.6:
fib
Exercise 5.7:
As
in
definition of
Exercise 5.8:
list-ref
Program
3.7
is
as
we might
expect.
displayed. Rewrite
is
5.3
is
not as complete
adequate information
ever,
is
Program
3.7,
how-
it,
using a letrec
displayed.
Scheme
is its
con-
We
By a
symbolic algebra we
mean a program
that
and
We
referred to as a
term
in
is
which
expressed in symbols by
akx^
hkx^
35z^. In general,
product
is
when we multiply
bk)x^
(ajt
real
c(ajkz*)
14s
cajt
number
(caifc)z*
c,
the
We may
also multiply
terms
a term with degree equal to the sum of the degrees of the two terms
is
and with
is
expressed symbolically by
Here
is
how
written as
21x^.
its coefficient.
3,
and 5x^
Terms
written as 5x.
is
terms of
like
we can only
arranged
of the degrees of
has degree
is
sum
of a finite
The
terms. Thus
its
4,
and
where the
+ an-ix^~ +
two polynomials
is
0,
of terms, usually
have coefficient
is
aix
bx^
12
all
The sum
of
Thus
of
3x^
is
the
ao
sum
is
of the form
+ a2X +
number
anX^
when added.
polynomial
maaimum
the
custom-
It is
coefficients
Two
by writing only
is
product of two
This
it
rule: the
5x^
and
12
7x^
Gx''
x^
llx
15
the polynomial
7x^
The term
leading term of
goal
nomials.
we
is
We
3x'*
to write
saw
5x'^
3,
term
12
4x2
+ llx-3
is
is 3x'*,
is
known
as
its
leading term,
known
as
and
leading coefficient
its
its
leading coefficient.
and
The
is 3.
programs that produce the sum and product of polysum in the discussion above, and later
Chapter
Our
9x'^
As
in
certain constructor
and
selector procedures
for polynomials have been predefined and return to their definition later in
this section
when we consider
143
We
the computer.
There are three selector procedures: degree, leading-coef and rest-ofpoly. If poly is a polynomial, then (degree poly) is the degree of poly and
,
(leading-coef poly) is the leading coefficient of poly. There is a zero polynomial, the-zero-poly, which has degree zero and leading coefficient zero.
Finally, (rest-of-poly poly) is the polynomial obtained from a polynomial
of positive degree, poly, when its leading term is removed. If poly is of degree
(rest-of-poly poly)
zero,
less
than
is
is
is
the-zero-poly.
called
poly-cons.
If
a nonnegative inte-
is
the leading term ax^ to the polynomial p. In particular, for any polynomial
(rest-of-poly poly))
is
poly.
We
shall
degree
less
than n
for
some
its
Thus
leading coefficient.
positive n, then
(poly-cons n
if
poly has
poly) evaluates
to poly.
We
Thus we
Program
5.6
define
is
whether both
zero-poly?
in
its
if
a polynomial
is
the-zero-
Program
5.6.
zero-poly?
(define zero-poly?
(lambda (poly)
(and (zero? (degree poly)) (zero? (leading-coef poly)))))
Program 5.7 shows how we build a term having degree deg and coefficient
coef The term so defined is itself a polynomial of degree deg consisting of
.
monomial.
If
A
we
make-term.
144
we
we
is
get
also referred to as a
its
define in
leading term by
Program
5.8 using
Program
meOte-term
5.7
(define make-term
(leunbda (deg coef)
Progrcon 5.8
leading-term
(define leading-term
(launbda (poly)
We
+ c)x*
also of degree k.
bx''
The sum
is
the
and
sum
ex''
if
of the
same degree
of two polynomials
like
is
If
polyl
their
If
is
sum
the-zero-poly,
is
their
sum
If
sum
sum
is
poly2;
if
poly2
is
is:
the-zero-poly,
is
is
If
the
sum
of
sum
is
rest of their
is
rest of their
polynomial that has the same leading term as poly2 and the
is
sum
sum
Our
polynomial that has the same leading term as polyl, and the
the
a term
polyl.
is
is
fc
coefficient of their
sum
is
rest of their
sum
is n,
5.9.
In this program, the use of the let expression enabled us to write each of
used the
let
more
concisely
expression, the
first
and more
clearly.
like
145
Progrun 5.9
p+
(define p+
(cond
((> nl n2)
((< nl n2)
(else
(degree poly2))
(poly-cons (degree polyl)
(leading-coef polyl)
(p+ (rest-of-poly polyl) poly2)))
let
expressions often
12x^
Now
+ 8x^ +
20x2
4x2 j^2>x^2
we
16x^
first
and
first
3x^
+ 2x^ + 4x + 5
+ Sx^ +
9x^+6x^ +
6x^ + 4x3
12x^
146
+ 20x2
12x2 + 15x
8x + 10
16x3
_,.
We now
9x^
14x^
+ 6x^ +
20z^
32x2
23x
10
product t* of a term trm and a polynomial poly. The algorithm for this
poly
If
is
product
is
coefficient of their
is
the
is
just
sum
product
the-zero-poly.
of the degrees of
rest of
trm
is
The
coefficient of poly.
is:
rest of their
poly.
If
polyl
is
just
is
the-zero-
poly.
Otherwise, we multiply the leading term of polyl by poly2, and add that
is
it is
is
defined locally
it
defines
is
p*-helper
is
The
is
not changed in the recursive invocations of the procedure being defined. Thus
better
Now
for X
5,
we substitute
5 for x
and get
when a number
4x^-|-8z^
7aj-|-6
147
Progrsun 5.10
p*
(define p*
(letrec
((t* (lambda (trm poly)
(if (zero-poly? poly)
the-zero-poly
(poly-cons
(+ (degree trm)
(degree poly))
the-zero-poly
(p+ (t* (leading-term pi) poly2)
(p*-helper polyl)))))
Program
5.11
negative-poly
(define negative-poly
(lambda (poly)
(let ((poly-negative-one (make-term
-1)))
Program
5.12
p-
but this
+ 8(5^) is
7(5)
very inefficient.
multiplying x by
lltS
results.
itself k
= 4x(5x5x5) + 8x(5x5)-7x(5) + 6
we evaluate this by computing each x* by
times and then multiplying the result by a^ we
If
number
is
we must add
n,
---
+n=
n{n
term
first
x( 7
8x
We
4x^).
its
+ 5(-7 +
+ x(-7 +
+ 5(4))). Whereas
5(8
original
are required
x(8
more contain a
For x
7
5,
+
in
this
in this last
form only
six operations
factor of x, so
we note that
we can
all
terms of
it
ai, to represent
our polynomial
factor
ao
We repeat
P{x)
or
polynomial
get
x(4))).
-|-
degree
we
becomes
x(ai
+ a2X + oax^
(-
term
Onx""-^)
as:
ao
By continuing
x(ai
x(a2
to factor out an x
asx
anx'^
^))
we
Oo
In this
method
x(oi
x(a2
x(a3 H
notation of Chapter
is,
like
x{an-l
XOn)
3,
(that
0{n)) while
is,
like
if
.)))
it
grew quadratically
when num
that (poly-value
is
substituted for x.
we think
the expression
that
(that
(-
is
poly num)
clue for
xon as a
coefficient
6,
then
149
poly-value
Progr2iin 5.13
(zero? n)
(leading-coef p)
(let ((rest (rest-of-poly p)))
(degree rest) (subl n))
(if
(pvalue (poly-cons
(subl n)
(*
rest))
(pvalue (poly-cons
(subl n)
(+ (* nuB (leading-coef p))
(leading-coef rest))
(rest-of-poly rest))))))))))
(pvalue poly))))
n 1,
that
than n
treats
is,
1,
This program
is
further operation
iterative since
is
performed
when pvalue
is
called in the
if
clauses,
no
Moreover,
first in
the
if
expression,
if
body of the
last let
it
expression reads
(poly-cons
...)))
The
last thing
polynomial
is
we
how
5x^
150
-3x2
-I-
X-
17
if
we want
to
Program
5.14
The
(Version
I)
(define degree
(lambda (poly)
(subl (length poly))))
(define leading-coef
(Isimbda (poly)
(car poly)))
(define rest-of-poly
(lambda (poly)
(cond
(define poly-cons
(cond
((and (zero? deg) (equal? poly the-zero-poly)) (list coef))
((>= deg-p deg)
poly)))))))
we simply write
(define pi (poly-cons 3 5
(poly-cons 2 -3
(poly-cons 1 1
-17 the-zero-poly)))))
(poly-cons
Using the concept of data abstraction again, we have been able to develop
a symbolic algebra of polynomials without knowing how the polynomials are
represented.
151
We
now
shall
ways
see several
in
which
polynomial
where we
is
completely determined
when a term
enter a zero
of the polynomial
then one
is
less
we
if
give a
of a given degree
of
list
is
its coefficients,
The degree
missing.
of coefficients.
list
nomial 5z^
7z^
21
list
(on On-i
is
On
Oo,
ai oq).
represented by the
is
haiZ +
-\
list
(5
suppressed in 5z^
representation of a polynomial as a
list
of
21),
7x^
21.
its coefficients is
adopted,
we can make the five basic definitions for the symbolic algebra of polynomials
shown in Program 5.14. Since we required that the leading coefficient of
a polynomial be different from zero, we put a zero test in the second cond
clause in the definition of rest-of-poly to skip over the missing zeros. In
as
the definition of poly-cons, the third cond clause guards against a leading
coefficient of zero,
Program
more than 1.
3.5 to
in
and the
fill
in missing zeros if
deg
differs
element
is
that term.
list
The
is
with
o^ 7^ 0.
We
polynomials as shown
There
may
first
the coefficient of
in
Program
The
those terms
algebra of
5.15.
152
is
is
that
The advantage
we only need
to define
the-zero-poly, degree,
Program
5.15
The
(Version
II)
(lambda (poly)
(caar poly)))
(define leading-coef
(lambda (poly)
(cadar poly)))
(define rest-of-poly
(leunbda (poly)
the-zero-poly
(cdr poly))))
(define poly-cons
(cond
((and (zero? deg)
coef)))
(list (list
((>= deg-p deg)
is still
valid with
rest of
our algebra of
no modifications.
Exercises
Exercise 5.9
test
in the
in the text.
polynomials
153
pi(x)
P2(z)
Sx"^
x^
7z^
6x^
2z
- 3z
and p2(-2).
Exercise 5.10
Look
Program
5.9).
When nl
is
greater than
of cond clauses.
Exercise 5.11:
poly-quotient, poly-remainder
polyl
is
when
is
divided by poly2.
Exercise 5.12
eis
lists
The
list
is
list
of
of pairs representation
given above can also be written in order of increasing degree. Consider the ad-
Exercise 5.13
How would
the constructors
and
selectors be defiined if
we use
in
lists
of pairs?
Exercise 5.14
The
definition
sively
it
oft*
in
Program
5.10
is
flawed.
Each time t*
invoked recur-
154
is
to be
(define p*
(let
(letrec
((t*-helper
(lambda (poly)
(if (zero-poly? poly)
the-zero-poly
(poly-cons
(+ deg (degree poly))
(* Ic (leading-coef poly))
(t*-helper (rest-of-poly poly)))))))
(t*-helper poly))))))
(lambda (polyl poly2) ...)))
append-to-list-of -zeros
version of poly-cons presented in Program
Exercise 5.15:
In the
to a
first
build the
list
of zeros
list
of zeros.
list
of zeros and
inefficient.
is
5.14,
poly
is
appended
list
of zeros.
list
One
is
to
list
and
5.4
test
them
in
iteratively.
zeros.
poly-cons.
Binary Numbers
Information
may
is
memory
1,
and
positions:
if it is off, it
is
which information
cells in
on and
off.
called a
bit,
and eight
If
is
a switch
0.
One
stored as a
is
on,
it
The information
bits of information
this section,
and more
5.4
we
different values
generally, as
Binary Numbers
numbers
in
binary form,
base.
155
Thus 4,723
the
is
same
10
is
a place-
is
counted.
is
as
4 X 10^
The
number
number
7 X
lOV 2
X 10^
number system.
3 X 10
We
in the base b
and
X 2^
X 2^
X 2^
X 2^
each
X 2^
digits,
example, for
X 2^
X 2
an2"
is
number
an_i2''-^
aiao.
We
first
ai2
+ oq
the decimal
number when we
precisely the
value
2.
number
degree
list
We
are given
as a polynomial of degree
k, for
A;
of the digits
which has as
We
its
last section if
This
is
ojfe
for the
term of
n.
define a procedure
binary representation.
is
one
less
in the
number.
If
number obtained when the first digit is removed, that is, for parameters (subl
deg) and (cdr Is), we get the polynomial for the parameters deg and Is by
adding the term having degree deg and coefficient (car Is). This leads us
to the definition given in Program 5.16.
Now to convert from the binary representation of a number to the decimal number, we use the procedure binary->decimal given in Program 5.17,
which takes a list of the binary digits as its argument and returns the decimal
156
Program
5.16
digits->poly
(define digits->poly
(lambda (digit-list)
(if (null? digit-list)
((make-poly
(lambda (deg Is)
(if (null? Is)
the-zero-poly
(poly-cons deg (car Is)
Program
5.17
binary->decimal
(define binary->decimal
(lambda (digit-list)
number. As an example, we
of the binary
number
number 11001101.
(binary->decimal
'
(1
1))
=>
205
we have a polynomial, say 1x^ + 1, which corresponds to the binary num1)? To do this, we
ber 101, how do we recover the list of binary digits (1
define a procedure poly->digits that takes a polynomial poly corresponding
to a binary number and returns a list of the digits of that binary number. For
If
example,
(poly->digits (digits->poly
'(11010
if its
is
1)))
degree
is
=>
one
(1
less
1)
just
5.4
Binary Numbers
157
Program
poly->digits
5.18
(define poly->digits
(lambda (poly)
(letrec
((convert
(lambda (p deg)
(cond
((zero? deg) (list (leading-coef p)))
'
(cons (leading-coef p)
(convert (rest-of- poly p)
(subl deg))))
(else
In order to do this,
which we
call
sidered, even
which
is
We
if
It
the coefficient
is
We
define
zero.
poly->digits
We
shall
do
this
shown
is
list
efficients an,
On-i,
...
p,
is
in
Program
its
5.18.
binary represen-
We
it is
also
tation.
convert.
of the term.
between the leading term and the next term with nonzero co-
in the degrees
efficient.
list
of the digits in
if
we
binary representation.
its
recall that
we want
number
q,
ao
2(ai
+ 2{an-i + 2an)
is
divided by
even,
2,
and
is
odd.
qo
ai
ao
If
we
1, is
q is
is
when
if 9 is
divided by
then we have
We now
2(02 H
1-
2(an_i
divided by
158
since q
2,
it is 1 if
or
2,
and so
forth.
In general,
if
is
-I-
2an)
when qo
quotient when ^jt-i
the remainder ri
qk is the
is
is
Remainder
Quotient
197
98
49
24
12
6
3
1
1
1
Figure 5.19
Conversion of 197 to
divided by 2 and
cik
if
rk
is
binary representation
its
when qk-i
the remainder
is
divided by
2,
then
rk-
shows
this
when
first
the successive
computation. Each
line
when the previous quotient is divided by 2. The binary representation of the number is found by reading the remainders from the bottom
the remainder
We
(decimal->binary 197)
Implementing
(1
this algorithm
is
then have
will
1)
parameter deg that keeps track of the degree of the term, starting from zero
We now
have
(decinial->binary (binary->decimal
(1
'
=*
0)))
=*
(1
0)
143
Two other number systems that are commonly used in computing are the
tal (base 8)
polynomial representation
5.4
Binary Numbers
is
oc-
replaced by
8,
and
is
159
Program
decimal->binary
5.20
(define decimal->binary
(lambda (num)
(letrec
((dec->bin
(lambda
(rI
deg)
(if (zero? n)
the-zero- poly
(P+ (make -term deg (remainder n 2))
(dec- >bin (quol,ient n 2) (addl deg)))))))
replaced by 16.
The
digits
digits 0, 1,2, 3, 4, 5, 6, 7, 8,
fi for 11,
9,
.
.
.
for
for 15.
Exercises
Exercise 5.16
Convert each of the following decimal numbers to base
2.
53
404
Exercise 5.17
Convert each of the following base 2 numbers to decimals.
a.
10101010
b.
1101011
octal->decimal, hexadecimal->decimal
Look over the programs for binary->decimal and deciraal->binary and
what changes have to be made to get definitions for the four procedures:
Exercise 5.18:
see
octal->decimal
hexade c imal ->dec imal
decimal->octal
dec imal->hexadec imal
160
pair of conversion
number
to be converted
integer.
Then
from base bl
n\un
bl b2)
and the
beise,
define a procedure
to base b2,
is
list
where the
bcise
where nxm
'
Exercise 5.19:
=^
(1
3 3)
(1
1)
16)
=*
(1 7
0)
13)
binary-sum, binary-product
Define two procedures, binaa"y-sum and binary-product, that take two bi-
of those
numbers
binary form. This can be done in two ways. First, you could convert both
numbers
You
numbers
using the appropriate carrying rules for binary numbers. Write programs for
Exercise 5.20:
binary->decimal, decimal->binary
We
have presented the conversions from binary to decimal and from deci-
mal
gebra.
5.4
Binary Numbers
161
Interactive
6.1
Programming
Overview
we begin by taking a brief look at the string data type. We
then illustrate some of the input and output features available in Scheme by
developing a program to find the square root of numbers. After implementing
the basic square root algorithm, we look at ways of viewing intermediate
In this chapter,
results
at
at run time.
We
two famous problems: the Tower of Hanoi and the Eight Queens problem,
6.2 Strings
Chapter
of operations
2.
number
is
written in
Scheme
sis
a sequence of
string?
tests
whether
its
argument
is
a string;
string-length takes a
string
substring
(or concatenating)
where string
is
a given string, and start and end are integers satisfying the
<
inequalities
start
is
is
It
end and
all
of the characters
start.
It is
also possible to
convert a symbol, such as 'hello into the string "hello" using the procedure
=*
16
(string-length "")
"
a string")
=>
=^
"This is a string"
"123456"
4) == "This"
=^ " i"
13) = "is
a str"
"hello"
^^
=
The
#t
#f
=>
same and distinguishes between upper- and lowercase. The predicate string-ci=? treats
upper- and lowercase as though they were the same character. (The "ci"
stands for case insensitive .) Thus the next to the last example above is false,
and the last example is true.
predicate string=? tests whether two strings are the
"We
string-insert that
first
inserts a string
stmg
so that the
The
by defining a procedure
definition
with indices
=>
less
than
n,
"12345678"
stmg
stmg
consist-
ing of those characters with indices n or greater. This gives us the definition
in
Program
We
6.1.
our discussions
164
shall introduce
Interactive
Programming
are needed in
Program
6.1
string-insert
(define string-insert
(string-append
(substring strng
n)
insrt
(substring strng n
(stiring--length
strng)))))
Exercises
Exercise 6.1:
substring?
Define a predicate substring? with two parameters, sstr and strng, that
tests
is
string-reverse
Define a procedure string-reverse that takes a
Exercise 6.2:
Hint:
You may
is
its
string as its
argument and
(define substring-ref
(lambda (strng n)
Exercise 6.3:
string
is
6.2 Strings
palindrome?
a palindrome
if
is
the
same
as the string.
165
For example, "mom" and "dad" are examples of palindromes. Define a predicate
palindrome? that
tests
is
a palindrome.
Test
ere
=^
saw elba")
=*
it
#f
The
forms
in
is
useful in an
its clauses.
if
expression that
These
include the special forms with keywords lambda, let, letrec, and cond. For
example, writing
(lambda (x y)
(writeln x)
(writeln y)
(+ X y))
is
the
same
as
(lambda (x y)
(begin
(writeln x)
(sriteln y)
(+ X y)))
expressions so that
(let ((a 3)
(b 4))
(writeln a)
(writeln b)
(+ a b))
is
166
the
same
Interactive
as
Programmtng
may
consist of several
(let ((a 3)
(b 4))
(begin
(writeln a)
(Hriteln b)
(+ a b)))
is
evaluated
if
the condition
is
true.
a^s if
of several
they were in a
begin expression.
Exercise
Exercise 6.4
An example
is
given below:
(define mystery
(leunbda (pos-int)
(letrec ((helper
(lambda (n count)
(cond
((= n 1)
(newline)
"
count
"
((even? n)
(writeln count
".
We divide
"
"
by 2.")
(writeln coiint
".
We multiply
"
(helper (+ (* n 3)
n
1)
"
by
(addl count)))))))
of (mystery 9)?
What
is
the output
ments. Safe recursive programs contain a terminating condition which eventually halts the computation. No one has, eis yet, been able to demonstrate
6.4 Input
and Output
positive integer
for
167
6.4 Input
and Output
We
have been using the keyboard to enter Scheme expressions, and we have
Scheme send
seen
its
root of a positive
number
of u and ^, that
by
is,
a better estimate
a,
is
where^
-^("+^)
Suppose we
We
(1)
(1) to
then substitute this value v for u in (1) to get the next value
we
we want
in the answer,
say
five,
We
get:
v.
v.
We continue
decide
we
compute
estimates that are the same to five decimal places. In particular, we shall stop
the calculation
To
0.000005.
when
test
and
v differ
whether u and
by
less
r are closer
(laabda (u v)
(abs (- u v)) tolerance)))
(<
We
1.
Make an
To make
that 5 X s
initial
estimate w
for the
square root of
a.
a.
If
the estimate u
better approximation to
their average
168
Interactive
i;
is
s.
is
Similarly
a better approximation to
Programmtng
s.
is
too small,
is
too
leirge,
emd
Program
square-root
6.2
(define square-root
(lambda (a)
(letrec
(
(next-estimate
(leunbda (u)
(close-enough? u v)
(if
(next-estimate v))))))
(next -estimate 1))))
2. If
is
an estimate
by the v calculated
3.
We continue
as the
is
given
in (1).
new value
of
u and
v differ by less
than tolerance.
Program
We
6.2
is
[1]
(square-root 100)
10.0
[2]
(sqrt 100)
10.0
[3]
(square-root 1000)
31.6227766016838
[4]
(sqrt 1000)
31.6227766016838
[5]
(square-root 2)
1.41421356237469
[6]
(sqrt 2)
1.4142135623731
we
compare its (presumably correct) results with our approximation. We see that
we got more than just five-decimal-place accuracy. This averaging method is
known to halve the error until the error is less than 1 in absolute value and
then to double the number of decimal-place accuracy with each successive averaging. In order to see that this
6.4 Input
and Output
is
actually happening,
it
would be interesting
169
We
it is
would
like to
send the
computed.
[7]
(begin
(display "Is")
(display
"
")
(display 1.4142)
(display
"
"
we have
to print
we want to print the string "the square root of 2?" on the next line,
we use the Scheme procedure newline, which takes no arguments and has the
effect of moving the cursor to the beginning of the next line. Scheme does not
specify a value for newline, and we again assume that our implementation
If
We now
(begin
(display "Is")
(display
"
")
(display 1.4142)
(newline)
170
Interactive
Programming
newline
line instead of
[8]
use
on the same
line as
Program
6.3
square-root-display
(define square-root-display
(lambda (a)
(letrec ((next-estimate (lambda (u)
(let ((v (/ (+ u (/ a u)) 2)))
(if (close-enough? u v)
(begin
(display v)
(newline)
(next-estimate v)))))))
(next-estimate 1))))
We now
6.3).^
in Figure 6.4.
We
behavior described.
round
to five places by
it
first
multiplying
round
to get 141421,
and
is
it
by l.Oe+5
100000.0), to get
(i.e.,
decimal places.
Then
places,
we
(square-root 2) rounded
off"
to five decimal
write:
=>
1.41421
places,
it is
convenient
Although the invocation of the local procedure next -estimate is within the begin exis still an iterative program, since the value of the recursive invocation of
next-estimate is returned directly as the value of next-estimate.
^
pression, this
6.4 Input
and Output
171
[9]
(square-root-display 100)
50.5
26.240099009901
15.0255301199868
10.8404346730269
10.0325785109606
10.0000528956427
10.0000000001399
10.
(square-root-display 1000)
[10]
500.5
251.249000999001
127.614558163459
67.725327360826
41.2454260749912
32.7452493444886
31.6420158686508
31.622782450701
31.6227766016843
31.6227766016838
[11]
(square-root-display 2)
1.5
1.41666666666667
1.41421568627451
1.41421356237469
Figure 6.4
Progreun 6.5
round-n-places
(define round-n-places
(lambda (n dec-num)
(let ((scale-factor (expt 10 n)))
(/
(define round-5-places
(lambda (dec-num)
(round-n-places 5 dec-num)))
172
Interactive
Programming
=^
1.41421
new line. Suppose we want to print out all of the successive values on one line.
Then we would not follow each application of display with an application of
nevline.
it
off
We would
values.
(if (close-enough? u v)
(begin
(newline)
y)
(begin
(display v)
(display
")
"
(next-estimate v)))
Here, (display v) prints the value of v to the screen; then (display
Thus the
"
")
numbers will
be separated by blank spaces. The final answer v will be on a new line. For
example, with the procedure squetre-root-display redefined this way, we
prints a blank space after the value of v.
successive
get:
[12]
(squcire-root-display 2)
1.41421356237469
out double quotes. For the occasions when we do want the double quotes to
be printed in addition to the string, we can use the Scheme procedure write
instead of display. If
[13]
we use write
instead of
display
in [8],
we
get
(begin
(write "Is")
(write
"
")
(write 1.4142)
(newline)
(write "the squ<u:e root of 2?")
(newline))
"Is"" "1.4142
6.4 Input
and Output
173
Program
read-demo
6.6
lambda ()
(display "Enter data (enter done when finished)
(let ((response (read)))
")
(cond
((eq? response 'done) (display "Thank you. Good--bye. "))
(else (display "You entered: ")
(write response)
(newline)
(read-demo))))))
We also see
that (write
whereas (display
it,
"
"
It is
around
When
is
running
is
invoked with no arguments, the computer stops and waits for an expression
returned by (read).
In
Program
6.6,
we
file
we
entered.
The
is
what we entered.
().
list
is
that
procedure of no arguments
is
(define greeting
()
[14]
(greeting)
174
Interactive
Programming
is
written as a procedure
in parentheses.
write
(lambda
it is
lambda expression
called a thunk, and it
in the
we
is
said to echo
first
In
called a prompt.
prompt
called as follows:
is
is
the
empty
invoked by
For example,
if
"
data.
The
let
first
is
produced by the read expression. During the evaluation, the computer pauses
and waits for us to enter a datum from the keyboard, and it is that datum that
is bound to response. We chose to use write instead of display to print the
response in order to show
it
exactly as
it is
it
is
double quotes. In order to stop the recursion, we enter done. The condition
terminating the recursion tests response to see
Here
is
the
if it is
same
as
done using
a symbol, and a string are entered in response to the prompt asking for a
in italics to distinguish
prompts.
[16]
(read-demo)
6.5432
Hello
"How
done
are you?"
We now
interactive-square-root
define
in such
a way that
it
prompts
Program
6.7
interactive-square-root
(define interactive-square-root
(lambda
(writ Bin "Enter the number whose square root you want
"
(eq? n 'done)
"
"
is
"
(squeire--root n))
(newline)
(interactive-square--root))))))
6.4 Input
and Output
If
to n.
When n
is
its
square root.
It is
procedure interactive-square-root
is
called,
is
repeated
[1]
(interactive-square-root)
Enter the number whose square root you want, or enter done to quit:
100
Enter the number whose square root you want, or enter done to quit:
1000
Enter the number whose square root you want, or enter done to quit:
done
That's all, folks.
it
prompts to
It
also
shows the
echoing of input data in the result to verify that the correct data were entered.
Study
this
we have
seen that output from our programs can be sent to the screen using the four
procedures display, write, newline, and writeln. Input from the keyboard
Exercises
Exercise 6.5
Write an interactive program that prompts for a number and then prints
the square and the square root of that number.
76
Interactive
Programming
It
numbers
until stop
is
Exercise 6.6:
The
entered.
and output.
Making change
and the user enters a number like 23.45. The program then tells how this
amount is made up of 100 dollar, 20 dollar, 10 dollar, 5 dollar and 1 dollar
bills and of quarters, dimes, nickels, and pennies.
The output should say
something
like:
Your change is
1 twenty-dollar bill
3 one-dollar bills
1
queurter
dimes
terminate
if
Exercise
6. 7;
Reverend
is
if
the
is
amount and
"no."
Zeller developed a
in the following
for another
The input
to the algorithm
is
for
any
specified
manner:
month
March
as
m=
1.
is
is
is
January
25, 1989,
4, 1989,
11,
m
=
5,
25, y
88,
2.
Take the
b.
3.
Take the
e.
4.
Compute f = a +
6.4 Input
and Output
and
89,
and
19.
The algorithm
to
is:
1.
b-\-e
4,
d-iry-2c.
177
5.
Set r equal to f
7.
6. T tells
to r
modulo
0,
Monday
etc.
1,
Write a program that prompts for the month, the day, and the year.
The
month should be entered in the usual way with January as 1 and December
as 12. The year should also be entered in the usual way (e.g., 1989). The
program should then convert these data to what is needed by the algorithm
and compute the day. The output should be a statement such as "1/13/1989
is a Friday." The program should ask whether another day is desired and
terminate
6.5
if
program
is
running.
The Tower
how information is
of Hanoi^ problem
is
The
In the great
pure gold which the priests carry one at a time between three diamond
needles according to
on a smaller
disk
is
finally in place,
come
the
End
of the World,
Brahma but on
and All
will turn
to dust.
We
left),
(for center),
and
posts, labeled
(for
(for right),
all
disks to the right post, so that at the end they will again be stacked in order
'
178
For a
fuller
Interactive
from bottom
at a time
Programming
larger disk
on
The Tower
Figure 6.8
of Hanoi
initial
disks.
we have solved
itself to
moving n
for
it
moving n
for
disks
disks
The
idea
that
is
is
With n
for
disks to
move
post
is
disk
empty.
R
is
the top
solution
We move
destination post R.
3.
We
as a help post,
have now solved the problem for n disks under the assumption that
is
for
disks.
If
disk (n
1),
the
To be
a single move that
destination by a
destination post. This case serves as the base case for our recursion.
able to write the solution to this problem, let us represent
carries a disk
from a post
called
source to a post
called
pair
L to C
is
(L R)
list
carries a disk
we
first
6.5
from
is
called
179
tOHer-of-hanoi and
its
(define toser-of-hanoi
(lambda (n)
...
))
We now
list
of pairs that
is
the solution of
the problem of moving n disks from the post source to the post destination.
definition with
(define tower-of-hanoi
(lambda (n)
(letrec
((move
...
is
the solution
is
list
is
(lambda (n)
(letrec
(
(move
Now
us to
for
>
any n
move n
)))))))
1 tells
1,
which produces a
list
first
disks
from the source post to the helper post making use of the destination post.
We
180
append
Interactive
to that
list
Programming
the
list
move from
the source
Program
tower-of-hanoi
6.9
(define tower-of-hanoi
(lambda (n)
(letrec
(
(move
(leunbda (n source destination helper)
(if
(= n 1)
(append
(move (subl n) source helper destination)
(cons
(list source destination)
The
resulting
list is
list
of
pairs produced by
making use
disks
(define tower-of-hanoi
(leu&bda (n)
(letrec
(
(move
(append
(move (subl n) source helper destination)
(cons
(list source destination)
)))
we
n disks located
on the source L and with destination R with the help of the post C. Thus the
complete solution is in Program 6.9.
Now
6.5
is
defined,
call it for
181
Program
display-tower-of-hanoi
6.10
(display s)
(display
"
>
'
')
(display d))))
(lambda (n)
(letrec
(
(move
(begin
")
Now
to solve the
C,
we
enter
(tower-of-hcinoi 3)
((L R)
(L C)
(R C)
(L R)
(C L)
(C R)
(L R))
This shows the seven moves that solve the problem for n
3.
list
as the answer.
Now we
ask
it
[3]
(display-tower-of-heinoi 3)
~>
>
C, R
L
C
182
~>
~>
R, C
R,
Interactive
>
~>
~>
Programming
in
Program
6.10.
With
this
to
list
new
It is
is
good practice to walk through the program and explain how the output
obtained.
The second problem we discuss in this section is that of the Eight Queens.
The challenge in this problem is to place eight chess queens on a chess board in
such a way that no queen is attacking any other queen.* How many different
solutions are there to this problem? One such is shown in Figure 6.11.
12
Figure 6.11
Let us
An
number
rows from
to 8 going
to 8 going
and the
The data structure we
from
left
problem
The queens
is
list
is
to right
list
of integers
by the position
list
(57263148)
list denotes the row of the queen in
we denote the positions of the three rightmost queens
on the board
in Figure 6.11
by (1 4 8).
We
call
a position
list legal if
none
For those not familiar with the rules of chess, a queen attacks another piece if the queen
are on the same horizontal, vertical, or 45-degree diagonal line.
6.5
183
Program
legal?
6.12
(define legal?
new-pl)))
(ceir
(and
(not (= next-pos try))
(not (= next-pos up))
(not (= next-pos down))
(subl down)))))))))
(define solution?
(lambda (legal-pl)
(= (length legal-pl) 8)))
(define fresh-try 8)
the
is
legal,
list
Program 6.12
When
that
is
failure.
184
in backtracking.
make
new
we
When we
solution?
start.
list, is
of length
We need
8.
We
need
a constant Iresh-
is
interesting because
it
represents a simple
a wrong guess and follow that wrong guess with other guesses
becomes
The undoing
Interactive
8.
list
it
list
list is legal.
until
position
often
The
because two queens are on the same row and the second because two
first
is legal.
list
list.
lists
of such guesses
Programming
is
will lead to
referred to as backtracking.
Program
build-solution
6.13
(define build-solution
(lambda (legal-pl)
(cond
Now we
6.
and they
1,
When we
all fail.
We
is 5.
decrease
backtrack.
recently
discover that
and
was the
17538)
(64
list
(17
it
try this
list
with
5, 4, 3, 2,
5 3 8).
0.
3, 2,
0,
nor
The
we can use
We
4, or 3,
2.
a five-position
list
from the
possibilities:
we
can
indicates
so
we cannot use
This
6, 5,
we
(8 2 5 3 8), (7 2 5 3 8), (6 2
among
If
list
To
is
6.13)
is
called,
hit a
list if
as far as possible
we know that
if it is
its
in Pro-
argument
so that
is
a legal position
If it is
(see
Program
6.14)
is
list,
This attempt
all
If
a position
0,
list.
If
This
not a
8).
in this
and (5 3
call
will
the try
is 0,
6.5
try
termination follows
we
we backtrack and
gram
list
to find a four-position
if
will
legal position
list.
list.
If not,
we
If so,
positions
the try
is
we invoke
try again.
185
Program
6.14
forward
(define forBard
Program
6.15
backtrack
(define backtrack
(lambda (legal-pl)
(cond
((null? legal-pl) '())
(else (forward (subl
We
(ceir
is
list
current position
With
list.
to the Eight
Queens problem.
[1]
(build-solution '())
(57263148)
Generalizing this program to get more solutions
that
how we
look at a solution
is
is
not
we notice
When we get a
difficult if
a matter of judgment.
186
Interactive
Programming
[2]
(define build-all-solutions
(lambda
()
(letrec
((null? sol)
'())
(length (build-all-solutions))
92
see
on three global
frees us
we
rely
how
to
problem work
make
By
variables.
is
a procedure that
As we have done
is
we
is
how
uninteresting because
it
the trace
we
vari-
list
will
make
the trace
more
readable.
(writeln "Backtrack
"
(writeln "Build-Solution
"
By
placing
and
6.5
187
Program
6.16
searcher
(define seeircher
((build-solution
(lambda (legal-pl)
(cond
(backtrack
(lambda (legal-pl)
(cond
(forward (subl
(ceir
(letrec
((null? sol)
'())
(build-all-solutions)
) )
we
get a trace. If we only want to trace until the first solution is found, as shown
below, then we replace the body of the letrec by (build-solution '()). As
you study the trace below, remember that the position list has been reversed,
and hence the last item in each list is the one most recently entered.
as the
188
first
Interactive
Programming
(2461357)
Exercises
Exercise 6.8
An
interesting question
move a tower
we can ask
to
move
the top
we
if
We
to take the
know that if
only one move to take
also
it
can
recall that
disks
disk,
Mn =
+ 2M_i.
and
We
are needed to
moves
is
Thus M\ =
it
1.
takes
Then
many
Exercise 6.9
Write a program that solves the Tower of Hanoi problem for n disks and k
posts. All of the disks are initially
on the
minimum number
first
post.
Exercise 6.10:
queens
6.5
189
nxn
board so that none attacks any of the others. Write a procedure queens
that takes n as an argument and solves the problem for an arbitrary n. Test
4,
3,
5,
and
6.
Exercise 6.11:
and
3's is called
a good sequence
appears twice
cis
(123231)
adjacent subsequences.
On
list
of
I's,
3) is
a good sequence. Methods similar to those used in solving the Eight Queens
all
find a
good sequence of
Exercise 6.12
Change the
list
of
definition of
the answers,
all
solution so that
it
build-all-solutions
it
Redefine your
Exercise 6.13
The backtrack
trace represents the search for the first solution of the Seven
You may
solve this by
hand
if
solution.
Exercise 6.14
is
to
remove
invocations of length.
Exercise 6.15
Sets of procedures can sometimes be combined.
190
new build-solution.
Interactive
Programming
Exercise 6.16:
blanks
As the number of
they become more and more difficult to
of blank characters.
we use
solution
is
to write a proce-
Run
the trace by
(define blemks
(IcUDbda (n)
(cond
((zero? n) "")
(else (string- append
6.5
"
"
191
Part 2
Procedures as Values
Procedures that take numbers as arguments and have numbers as values are
Examples are addition and multiplicaProcedures that take procedures as arguments and have procedures
consuming
activities.
but
it
can be
made
to
work
the
is
an ab-
We
in
still
enter, pay,
out procedure,
we
and
exit, so
we can
refer to
it
as the
consuming procedure.
ing,
menu and
then we will once again have the dining out procedure, but
if
we
will
If
eat-
feed
it
have the
movie-going procedure.
some
or
all
is
Set theory
is
tell
us whether
about collections of
8,
we develop a
set algebra
^^4
Procedures as Values
is
Abstracting Procedures
7.1
Overview
we first see how procedures can be passed as arguments to
other procedures and how procedures may be the values of other procedures.
We illustrate these ideas with a development of the Ackermann procedure.
We then show how a procedure of two arguments may be rewritten as a
procedure of one argument whose value is a procedure of one argument. This
In this chapter,
process
is
called currying.
in structure
We
in
used easily to generate any other program with these features. This process
called procedural abstraction.
in
That
7.2
Flat recursion on
is
is
it
as the
first
lists is
often encountered
In this section,
we
shall
1,
we included procedures
value in Chapter 3, we passed the procedure > as an argument to the procedure extreme-value. In Scheme, all procedures may be used as arguments
to other procedures and as values of procedures. This idea is illustrated by
many examples
in this section.
Suppose we have a
list
of numbers, such as
(13
to
Program
map
7.1
(define map
(null? Is)
'()
produce a new
the
list,
list
that
is
(2468
list
to each item in
We
10).
can define
list
1.
(define addl-to-each-item
(lambda (Is)
(if (null? Is)
'()
(cons (+
Now
if
we want
add
to
(+1
(car Is))
2 to each element,
we have
different operations
may
list,
it
(map addl
'
efficient if
(1 3 5 7 9))
definition of map
is
=>
(2 4 6 8 10)
To add
2 to each
We
(+
num 2))
'
(1 3 5 7 9)
=*
element in the
(+
num 2)), as
(3 5 7 9 11)
lists
as
its first
196
Abstracting Procedures
(d e)
h))))
=>
(a b c)
(a d e)
(a f g h))
Program
7.2
lor-each
(define for-each
(begin
(proc (car Is))
(member? x Is))))
(bed)
must be of the
(c d a)))))
=*
(#t #f #t)
list
is
to
map
applied to them.
In
first of these two examples, proc is a procedure that takes a list as its
argument and conses the symbol a onto the list. Thus each element of the
the
is
list,
and the
list
that
is
returned consists of
it.
that
is
returned
list,
unspecified, that
is
[1]
we
is,
definition of
eire
it
for-each
is
An
is:
Hello. How
We
you?
is
We
first
the procedures
eters. Its
syntax
7.2 Procedures as
list
of param-
is
197
(Isunbda (parameteri
expri expr2
in the list of
25
(add
3 5 7 9)
(add
3 5 7 9
11) ==* 36
(add
3 5 7 9
11
It is
13)
49
and
it
may
bound
in the
to the
body
Program
of
is
(danbda var
If
number
list
expri expr2
of arguments (argi
.).
The
7.3
operandi ...)
.,
is
.
eff'ect.
add
(define add
(letrec ((list-add
(laabda (Is)
(if (null? Is)
(+ (car Is)
(lambda
eurgs
(list-add args))))
As an example. Program
produces the
198
sum
of
its
7.3
12
3 4 6)
=^
16.
Program
list
7.4
Program
writeln
7.5
(define writeln
(lambda arge
(for-each display
<irgs)
(newline)))
Program
error
7.6
(define error
(lambda args
(display "Error:")
"
")
(nevline)
(reset)))
The
a
list,
and
so
we
let it
args as
its
remember that
eurgs
is
argument.
stricted
to
Two
is
'c
'd)
list
is
defined in
Program
7.4 so that
(a b c d)
procedures, writeln and error, can also be defined using the unre-
Programs
in
7.5
and
7.6.
The procedure
of no arguments reset in
We
maximum
list
Is
is
of two
numbers
in
list
Is.
7.2 Procedures as
maximum
We
could write
199
Program
add
7.7
(define add
(lambda args
(if (null? args)
(+ (car args)
has the
is
the
call structure
where the procedure proc takes the same number of arguments as the number
of items in the
list
Hst-of-items.
It
when we invoke
arguments. For example, we can
its
call
=* 4
ID) =^ 15
The
restricted leunbda.
Program
way
7.7 illustrates
it
given in Program 7.3, this time using apply in the recursive invocation of add
on the
list
of numbers, so
of numbers.
it
is
to invoke
in the
number
is
list
list
(cdr
args).
3 5 7 9)
=>
=>
(+ 5)
(+)
(* 2 4 6)
(
(*)
200
=>
25
48
5) == 5
=>
number
(ax
(in
An
-10 15 -20)
15
-10 15 -20)
=*
-20
object in
Scheme
is
if it
can be petssed as
be bound to
We
it.
may
or lists of
is
many
other
programming languages.
To
we first look at the compositwo functions from a mathematical point of view. Assume that / and
g are functions that take one argument and that each value of the function g
is a valid argument of the function /. We can then speak of the composition
discuss the composition of two procedures,
tion of
h of the
by h{x)
fig{x)): that
is.
we
first
evaluate g at
and then invoke / on the value gix). This idea can be interpreted for the
procedures we use in our programs. We now define a procedure compose that
X.
is
Program
compose
7.8
(define compose
(labda
(f g)
(laabda (x)
(f
The body
(g x)))))
of the
first
the procedure
(laabda (x)
(f
(g x)))
and we invoke
this
7.2 Procedures as
Arguments and
\'alues
201
an example,
let
Then we can
define the
composition h by writing
is
argument. This
illustrates
is
to x
itself
a procedure of one
sqrt and addl, as arguments to a procedure and we can have the value of a
procedure be a procedure.
If
we
The procedure k
so defined
first
A:(x)
^Jx-\- 1.
Thus
its
is
argument and
quite a diff"erent
function from h.
Exercise
Exercise 1.1
What operand do we
We
same value
eis
(h 8)?
esting
example that
in
The procedure
7.9.
we can add
to x repeatedly
be defined in terms of plus and subl as shown in Program 7.10. This says
that multiplication of positive integers x and y
itself
eis
the
same
as adding x to
multiplying x by
shown
202
is
in
Program
7.11.
Abstracting Procedures
Program
7.9
plus
(define plus
(Icimbda (x y)
(if (zero? y)
X
(addl (plus X (subl y))))))
Program
times
7.10
(define times
(lambda (x y )
(if (zero? y)
(plus X (times x (subl y))))))
Program
exponent
7.11
(define exponent
(Icimbda (x y)
(if (zero? y)
1
Program
7.12
super
(define super
(lambda (x y)
(if (zero? y)
1
The
three procedures
we can define
exponent and subl, as shown
evaluate (super 2 3).
pattern,
7.2 Procedures as
in
Program
7.12.
What
this
uses
203
Program
superduper
7.13
(define superduper
(lafflbda (x y)
(zero? y)
(if
Program
super- order
7.14
(else (lambda
(3:
y)
(cond
((zerc>? y)
1)
z
((super -order n) I (subl y))))))))))
(super
3)
^^
=*
(erponent
=*
^^
^^
=>
(exponent
(exponent
(exponent
(exponent
4)
16
2 3)
is
(super 2 2))
Thus (super
(a tower of 4 twos),
2^
which
In the
is
We
get that
see that
like 2
0))))
2 2))
same way we
65,536.
and
super
(super 2 4)
yields large
is
2^
numbers
4.
in
Program
and (superduper
This
is
is
is
We can
make up
204
7.13.
2 4)
new name
Abstracting Procedures
It
would be better
to define a procediire
definition of
the
is
same
and
as plus,
is
if
given in
is 2,
Program
7.14.
If
then super-order
is
is
the
super-order
same as times.
1,
We
n,
for
16.
can now write any procedure in the sequence by selecting the appropriate
value for the parameter n in (super-order n). For example, the procedure
that comes after superduper
If all
is
is
(super-order
called the
Program
Ackermann procedure.
6).
it
Specifically,
ackermann
7.15
(define ackermemn
(lanbda (n)
((super-order n) n n)))
Then
(ackermann
1)
1)
(ackermanx. 3)
(exponent
To
how
get an estimate of
256.
logioz
4"*
.
4^
To estimate
256logio4
Finally
similarly.
10^^'*0.602.
3)
which is
2.
which is
4.
which is 27.
which is
large
= 4^^,
= 154.13. Thus we
get 4^^^
we estimate
If
we
set
Then y
proximately 10^^^
digits.
certainly does
7.2 Procedures as
grow
fast as
n increases.
205
We
is
itself
how procedures
a procedure with
and
Scheme.
We
y,
il-
shall
explore these ideas further in the next section, which deals with procedural
abstraction.
Exercises
composes
Exercise 7.2:
/. g.
and
h,
f{g{h{x))).
compose -many
ExeTcise 7.3:
many
subtract
Exercise 7.4:
plus, times,
etc.,
define
and
y,
with x
>
y.
y.
Exercise 7.5
In the following experiment,
[1]
fill
(let
[2]
(cons i i))
(+ 5 i))
'((12)
[3]
'(1234))
[4]
(let
((n 5))
(let
206
Abstracting Procedures
(3
4)
(5
6)))
[5]
(define iota
(lambda (n)
(letrec ((iota-helper
(lambda (k ace)
(cond
((zero? k) (cons
ace))
(else (iota-helper (subl k) (eons k ace)))))))
(iota-helper (subl n) '()))))
[6] (letrec ((fact
(lambda (n)
(if (zero? n) 1 (* n (fact (subl n)))))))
(map fact (iota 6)))
[7]
(+ x
(addl x)))
(iota 5))
[8]
(define mystery
(lambda (len base)
(letrec
(
(mystery-help
(lambda (n s)
(if (zero? n)
(list s)
(let ((h (lambda (i)
[9]
map-first-two
Define a procedure, map-first-two, that works exactly like map except that
the procedure argument is always a procedure of two arguments instead of
just one argument. Use the first and second elements of the list as the first
pair of arguments to the procedure, then the second and third elements, then
the third and fourth elements, and so on, until the end of the list is reached.
If there are fewer than two elements in the list, the empty list is the value.
Exercise 7.6:
(map-first-tHO + (2 3 4 5
(map-first-two max '(2 4 3
'
Exercise 1.1:
=>
(5 7 9 12)
5 4
1))
=> (44554)
7)
reduce
Define a procedure, reduce, that has two parameters, proc and Is.
procedure proc takes two arguments. The procedure reduce reduces the
7.2 Procedures as
The
list
207
original
is
When
applied to them.
how
is
the
list
it
builds a
new
with the
list is
first
when proc
list
list
is
reported.
when proc
is
Here
and Is
is
(3 5 7 9):
(3 5 7 9)
->
(8 7 9)
(15 9) -* 24
(reduce +
'
(1 3 5 7 9))
(reduce max
'
=J> 25
(2 -4 6 8 3 1))
=>
The
and
last
is
example
8
'
(#t #t #t #t))
is
'
=>
#t
Exercise 7.8:
list.
andmap
list
Is.
(define andmap
(and x y))
Exercise 7.9:
#t
map2
=>
is
its
it
procedure argument
takes an additional
argument that is a list the same length as its second argument. The additional
list is where it gets its second argument. Test your procedure on:
(map2 +
208
'(1234) '(579
Abstracting ProceduTes
11))
=>
(6 9 12 15)
(inap2
(leunbda (x y)
(and
'(13
X n)
'(9 11 4 7 8))
Exercise 7.10:
We now
n y))))
7)
=>
(#t #t #f #t #f)
map, ormap
(map proc
where proc
the
same
is
Isi
I32
number
of arguments.
...Isn)
lists
has
(define map
(leunbda args
(letrec ((map-helper
(lambda (a*)
(if (any-null? a*)
()
(cons
is
two invocations of
map
within the definition refer to the simple map we defined earlier in the chapter.
Add a definition of the simple map to the letrec (in the same way that even?
and odd? are in the same letrec) so that no names will be changed in the
definition of map-helper, and write zmy-null? using the definition of ormap
given below.
(define ormap
(null? Is)
#f
(or (pred (car Is))
What
7.2 Procedures aa
lists
209
Exercise 7.11
To
test
7.3
Currying
The procedure
+ takes
We
their
sum. The
argument by writing
its
(define add5
(lambda (n)
(+ 5 n)))
5.
Another way of
its value.
We
may
return
only one parameter, m, and returns a procedure having one parameter n, that
adds m and
n:
(define curried+
(lambda (m)
(lambda (n)
(+mn))))
Thus (curried+ 5) returns a procedure defined by
(lambda (n) (+ m n))
where m
is
bound
to 5.
((curried* 5) 7)
We
To add
and
12
210
7,
and we
do the same
clearly can
underlies this
method
is
for
y,
What
in place of 8.
and rewrite
it
y.
The
process of writing a
is
It is
often
advantageous to use a curried procedure when you want to keep one argument
fixed while the other varies, so in essence,
argument.
We
way
we
common
In
defined as follows:
(define member?
(Icunbda (item Is)
(if
(null? Is)
f
It tests
is
list
Is.
We
are
going to apply the procedure member? with the same object item but different
lists
Is, so
we
member?-c, which
is
a procedure
with parameter item and returns a procedure that has the parameter Is and
tests
whether item
is
a top-level
of Is.
We
in the definition of
do that
in
Program
7.16.
member?-c:
1.
member?-c
2.
is
member
returns a procedure
eter Is.
Conceived by Moses Schonfinkel in 1924 (See Schonfinkel, 1924) and neimed after the
7.3 Currying
211
Program
member?-c
7.16
(define member?-c
(lambda (item)
(letrec
((helper
(lambda (Is)
(if
(null? Is)
#f
(or (equal? (car Is) item)
helper)))
We
3.
call, since
We
in
by writing
(define member?
(lambda (a Is)
((member?-c a) Is)))
(map addl
Its definition
'
(1 2 3 4)
(2 3 4 5)
is:
(define map
(null? Is)
'()
in curried
We
give
its
definition in
apply-to-all by defining
212
Abstracting Procedures
is
Program
itself
7.17.
We
Program
apply-to-all
7.17
(define apply-to-all
(lambda (proc)
(letrec
(
(helper
(lambda (Is)
(null? Is)
(if
'0
(cons (proc
helper)
Program
(cir
Is))
sum
7.18
(define sum
(letrec
(
(helper
(lambda (Is)
(if (null? Is)
(+ (cai Is)
(helper (cdr
Is0))))))
helper)
Program
product
7.19
(define product
(letrec
(
(helper
(lambda (Is)
(if (null? Is)
1
(*
(cai Is)
helper)
(define map
7.3 Currying
that take
lists
as arguments.
The
first,
213
Program
swapper-m
7.20
(define swapper-m
(laMbda (x y)
(letrec
((helper
(laabda (Is)
(cond
((null? Is)
'())
(cao:
Is)
helper)))
We
list,
list
are
in the
list.
and apply-to-all.
We
without the
able to
section.
We
an example that
is
We
is:
look at the
(define swapper
(laabda (x y Is)
(cond
((null? Is) '())
We
214
modify
it
to get a procedure
((swapper-m
1)
'
(0
2))
=>
(1
2)
re-
More
generally, a procedure o{ n
to get a procedure of
m-j- k arguments
first
argument
may
be modified
is
Exercises
curried*
Exercise 7.12:
to get a procedure
its
on:
swapper-c
Exercise 7.13:
Curry the procedure swapper-m so that the curried procedure swapper-c has
one parameter x. It returns a procedure with one parameter y, which in turn
returns a procedure with one parameter Is.
in Is.
round-n-places
procedure round-n-places was defined to take two parameters, n and dec-num, and returned the number dec-num rounded off" to
n decimal places. Rewrite the definition of round-n-places so that it takes
Exercise
In
7.14-'
Program
6.5, the
n,
7.3 Currying
number
off"
215
Exercise 7.15:
subst-all-m
Modify the deeply recursive procedure subst-all, which has the parameters
new, old, and Is, to get a procedure subst-all-m with the two parameters
new and old, which returns a procedure with the parameter Is, which replaces
each occurrence of old in Is by new. Test your procedure on:
((subst-all-m 10)
((subst-all-m 1 0)
(0
'(0
((0
'
=>
2)
2))))
(1
=>
2)
(1
((1
2)))
extreme-value-c
In Program 3.19, the procedure extreme-value was defined and then it was
used to define the procedures rmajc and rmin by pcissing it the appropriate
predicate. Write the definition of the procedure extreme-value-c, which
Exercise 7.16:
its
its
finds the
maximum
Exercise 7.17:
extreme-value-c
lambda
(extreme-value-c pred)
is
a procedure that
takes arbitrarily
(maximum
or
Exercise 7.18:
value
between?, between?-c
and returns true when y is strictly between x and z, that is, when x < y <
z. Then define between?-c, a curried version of between?, where each of the
procedures has only one parameter. That is, between?-c has the parameter
X and returns a procedure that has the parameter y, which in turn returns
a procedure with the parameter
and
z.
z,
(((betHeen?-c 5) 6) 7) =^ #t
(((betBeen?-c 5) 5) 7) => f
(((betHeen?-c 5) 4) 7) == #f
Exercise 7.19:
andmap-c, ormap-c
216
Abstracting Procedures
is
strictly
between x
(define emdmap-c
(lambda (pred)
(letrec
(
(and-help
(lambda (Is)
(cond
and-help)))
Fill in
[1]
[2]
7
[3]
[4]
(c)
(c d e)))
Now
ormap-c as
list
as a value.
argument
We
(c)
(c d e)))
follows:
(define ormap
Test ormap-c by
[5]
[6]
filling in
7
[7]
[8]
9
Exercise 7.20:
(a b)
is-divisible-by?, prime?
(lambda (k)
(zero? (remainder n k)))))
7.3 Currying
S17
A prime
Why
is it
necessary only to
Exercise 7.21
Justify the statement "If we restrict ourselves to using only
its list
of parameters,
lambda expressions
we can
still
define
any
examples
in this section
7.4
we show how
We
by looking
for
common structural
and product
(letrec
((helper
(lambda (Is)
(if
and the
leist
(null? Is)
line
helper
are identical in
to (car Is)
all
we do something
helper on (cdr Is). We want
call to
all four,
programs; that
218
is,
it
Abstracting Procedures
embodies the
(define flat-recur
(Icunbda
(letrec
(
(helper
(Icu&bda (Is)
))))
helper)))
How
do we
in the
fill
consequent of the
We
call this
if
blanks?
expression.
Let us
It
is
first
when Is
first
parameter
in the outer
is
it
is
the
empty.
by the
lambda expression.
Table 7.21 shows the seed for each of the four cases.
Procedure
seed
inember?-c
#f
apply-to-all
sum
product
Table 7.21
The
if
expression
is
is
in the action
is false.
The
call this
procedure list-proc.
y.
We
write
When list-proc
is
bound
to (caur Is)
If
list-proc
is
the value of
then
219
in the outer
lambda
We pass
list-proc
expression.
four programs.^
Procedure
list-proc
member?-c
apply-to-all
sum
product
The
Table 7.22
We
are
four
now ready
and list-proc
as
list
procedures
We can now
list
(See Pro-
to write
of top-level items.
flat-recur
as follows:
(define member?-c
(lambda (item)
+))
The procedure
cessing than
first
is
argument
*))
necessary, for
to or
is
it
is
220
Abstracting Procedures
is
called,
Program
7.23
flat-recur
(define flat-recur
(helper
(laabda (Is)
(if
(null? Is)
seed
(list-proc (car Is)
helper)))
different structure
from those
list-proc
in the first
two ex-
in these last
is
programs.
It
is
similar
is
it is
is
a very
applicable.
the object
returns a
is
list
to be
list.
f ilter-in-c
test.
This
program involves recursion on the top-level objects in the list Is, and if Is is
empty, f ilter-in-c returns the empty list, so seed is (). To get list-proc
we shall again use x for the (car Is) and y for (helper (cdr Is)). Then
if pred applied to x is true, we cons x to y; otherwise we just return y. Thus
the list-proc of flat-recur can be written as
(lambda (x y)
(if
(pred x)
(cons X y)
y))
Recursion
221
Program
f ilter-in-c
7.24
(define filter-in-c
(lambda (pred)
(flat-recur
'()
(lambda (x y)
(if (pred x)
(cons X y)
y)))))
and we can
to use
filter-in-c
define
filter-in-c
in
as
as:
(define filter-in
'
(1 2 3 4 5 6 7 8 9))
(filter-in positive?
'
We
flat recursion.
that use
flat
we have
(1
x 5))
4))
3
'
= (1 3 5 7 9)
=> (1 2 3 4)
(1 2 3 4 5 6 7 8 9))
=>
(1 2 3 4)
defined a procedure
arguments. This
easier to write
is
and
a powerful tool
to understand.
Exercises
mult-by-scalar
we called a list of numbers an n-tuple. Using flat-recur,
deflne a procedure mult-by-scalar that takes as its argument a number c and
returns a procedure that takes as its argument an n-tuple ntpl and multiplies
each component of ntpl by the number c. Test your procedure on:
Exercise 7.22:
In Exercise 3.1,
222
((mult -by-scalar 3)
'(1-2
((mult-by-scalar 5)
'())
Abstracting Procedures
3 -4)) =*>
=>
(3 -6 9 -12)
Exercise 7.23:
filter-out
It
test,
is
that
true.
is, it
list
Is
all
of
its
pred and a
list
for
out-c that
is
insert-left
Exercise 7.24:
Starting with the procedure insert-left described in Exercise 4.1 and using
flat-recur, define the modified version insert-left-m that takes as pa-
rameters the new and old values and returns a procedure with the
list
as
its
partial
Exercise 7.25:
(proc
i) for
of the
numbers
(*
=*
m m)) 3 7)
135
numbers (proc
i) for i
sum
3 7)
=^
<
n. For
example
6350400
named par-
7.5
sublists rather
display a
recur.
common
lists.
They
also
common
structure
We
list
Is as
its
Deep Recursion
its
argument and
223
from the
Is, drops
if
pred
list
odd? and Is
is
The code
in-all
=>
((5)
(3 5
(7)))
filter-in-all-c is given in Program 7.25. We define lilterthe procedure of two arguments, pred and Is, in terms of filter-
for
as
Program 7.26.
In the same way, we define sum-all as a procedure of one argument Is,
which is a list of numbers, such that (sum-all Is) is the sum of all of the
numbers in Is. For example
in-all-c
as
shown
in
The code
for
sum-all
12
is
lines:
(letrec
(
(helper
(lambda (Is)
(if (null? Is)
(or (pair? a)
(null? a))
helper
We
deep-recur
how much
of the code
(define deep-recur
(lambda
(letrec
((helper
(leunbda (Is)
(or (pair? a)
(null? a))
))))))
helper)))
224
we can
fill
in
from
Program
(define
f ilter-in-all-c
7.25
f ilter-in-all-c
(Icunbda (pred)
(letrec
((helper
(lambda (Is)
(if (null? Is )
'0
(let ((a (car Is)))
(if (or (pair? a)
(null? a))
(cons (helper a)
(if
(pred a)
(cons a
(1-
helper)
Program
7.26
filter-in-all
Program
7.27
sum-all
(lambda (Is )
(if (null ? Is)
(or (pair? a)
(null? a))
(+ (helper a)
helper))
Deep Recursiori
225
Once
if
again,
parameter
lambda
seed
),
().
We
and
first
expression.
(null? a)
is
is 0,
if
helper
for
lilter-in-all-c invokes
and the
local procedure
helper
for
sum-all invokes
(+ (helper a)
We
refer to the
procedure that
Is)) as list-proc.
We
fill
is
and to generate the expression needed for f ilter-in-all-c. we bind listproc to cons, and to generate the expression needed for sum-all, we bind
(or (pair? a)
(null? a))
is
if
expression with
(if (pred a)
We
can generate both of these using a procedure item-proc that has two
parameters, x and
y. If
we
fill
we need
226
for
to
+.
To
get
what
Program
deep-recur
7.28
(define deep-reciir
((helper
(leunbda (Is )
(null ? Is)
(if
seed
(let ((a (car Is )))
(if (or (pair? a)
(null? a))
(list-proc (h Blper a)
Is.)))))))))
helper)))
(lambda (z y)
(if (pred x)
(cons z y)
y))
We
are
now
in
the structure of these procedures (and those in the exercises at the end of
this section).
It
hcis
is
parameter Is. Combining the observations made above, we get the definition
presented in Program 7.28.
In particular,
+ +))
anc
(define
f ilter-in-all-c
(lambda (pred)
(deep-recur
'()
(lambda (z y)
(if (pred z)
(cons z y)
y))
cons)))
Deep Recursion
2S7
tures
and took
as
common
to
them
all.
flat
flat-recur
recursion from
common
features
and defined the procedure deep-rec\ir. We were able to recover the original
two procedures by passing to deep-recur the appropriate arguments. This
process of defining a procedure incorporating the
common
structural features
is
what we
called proce-
dural abstraction.
Exercises
remove-all-c. product-all
Exercise 7.26:
The
list
call
of
list
Is,
which removes
all
Is.
argument and
re-
numbers
its
lists.
all
of the
numbers
in the
Exercise 7.27:
Exercise 7.28:
In a
filter-out-all
manner analogous
deep-recur
it
to define
to define
filter-out-all.
subst-all-m
The procedure subst-cQl-m was described
Exercise 7.29:
deep-recur.
228
in Exercise 7.15.
Define
it
using
reverse-all
The procedure reverse-all was defined
deep-recur.
Exercise 7.30:
in
Program
4.10.
Define
it
using
flat-recur
Define flat-recur using deep-recur.
Exercise 7.31:
deep-recur
Define deep-recur using flat-recur. Hint: Use letrec.
Exercise 7.32:
Deep Recursion
229
8.1
Overview
Sets play a fundamental role in the development of mathematics and logic.
we show how
In this chapter,
Scheme.
many
We
sets
may
first
how
quantifiers.
We
set operations.
we
is,
In the last
We
We
section,
the discussion,
8.2 Quantifiers
discussion of sets.
tell
If
whether both, at
we
we
how many
some
condition.
hence these procedures are called quantifiers. In this section, we introduce the
quantifiers both,
we add
to this
list
after sets
and none.
The
first
of these
is
It is
true
if
and only
if
pred
is
its
ajrgl
and
It is
easy
Program
both
8.1
(define both
(lambda (pred)
(lambda
(zirgl
arg2)
For example,
if
we want
to test whether
two
lists
we
on the two
lists.
Then
'
(a b c)
'(d e))
=>
Thus
((both (compose not null?)) '(a b c)
We similarly define
pred.
Its
It
value
Here
'(d e))
is
is its
true
if
and only
if
definition:
8.2
neither
(define neither
(Icunbda (pred)
Thus
Sets
#t
returns another predicate that has two parameters, argl and eu:g2.
Program
232
=^
and Relations
(pred arg2))))))
is
true.
((neither null?)
'(a b c)
and
It
Below
is its
Program
=>
'(d e))
is
its
parameter a
when
true
either
is
true.
definition:
at-least-one
8.3
(define at-least-one
(lambda (pred)
(lambda (argl arg2)
(or (pred argl)
Here
is
how
it
(pred arg2)))))
works:
((at-least-one even?)
3)
^^
#f
((at-least-one even?)
2)
^=
#t
We
little
to
it.
For example,
let
us take neither as the basic one and try to express both and at-least-one
in
lists, if
we want
lists is
same
is
the
them
irgl
arg2))))
in
both places.
We
can
8.2 Quantifiers
233
iname x
.) is
the
same
as iproc x
.).
For example,
same
as cons.
which appears
be
We
(define both
(lambda (pred)
(lambda
(eirgl eurg2)
We
arg2))))
is
eurgl
the
same
(curgl eurg2)
as
so
we obtain the
final version of
both
to be
(define both
(lambda (pred)
(neither (compose not pred))))
This kind of simplification was possible because we curried out the parameter
definitions.
234
Sets
and Relations
way we
verbalize
it
in
English.
satisfy
In a similar manner,
defined in
terms of neither by
(define at-least-one
(lambda (pred)
(lambda
(eirgl
arg2)
least
when
it is
not
Exercises
Exercise 8.1
Show
and that
the other two, neither and at-least-one, can be defined in terms of both.
Exercise 8.2
Start with
in
at-least-one
terms of at-least-one.
Exercise 8.3:
equal?
Use the procedures of this section to write a definition of the Scheme predicate
equal? that
pressions
is
tests
a pair,
If
it
it
recursively
predicate on
(equal? '(a
(be
(d e) f ))
'
(a (b c (d e) f ) ))
=>
'
8.2 Quantifiers
#t
(a (b d) c e)) ==> f
235
8.3 Sets
In this section,
We treat sets
called sets.
later
as an abstract
first
assume and
An implementation
sets.
of sets must begin with the specification of the kinds of objects that are
all
is
The
members of the
set.
and enclose
and c is written as
may
{a,
a, b,
and
{d, e}.
is
set
a set or
it
lists
and
of the element a
set,
consider
empty-set. There
We
it
makes no sense
This
set.
is
is
is
b,
c} and {6,
c,
how we implement
is
We denote
sets.
set? that
tests
the
is
a} represent the
lists.
empty
we assume
is
is
If
obj
is
sets,
s is
all
set,
If
obj
is
236
Sets
we now proceed
and Relations
There
set as its
member
is
not
of a set.
an object and
sets.
pick takes a
called adjoin.
operators,
selector
set.
an object and
a sameness
equal?.
by the-
The base
set.
is
set
empty: empty-set?.
whether an object
We now
while we
lists,
predicate, which
to speak of
an important distinction
We now
no
is
same
sets, since
not;
is
between
empty
as 0.
it
in
is
c}.
There
Either an element
b,
all
s is
of the
set,
members
s.
If
obj
is
not
The constructor
s.
With
these basic
We
begin with the definition of a procedure make-set that takes any num-
If
add the
when using
8.4
We
use
all
first
recursion
Program
'b
flat
'a
is
msdce-set
(define meike-set
(lanbda args
(letrec
(
(list-meJce-set
(Icunbda (args-list)
(if
(null? args-list)
the-empty-set
(adjoin
(car eirgs-list)
In Section 8.2,
we introduced the
We now
The analog
of
For example,
(let ((s (make-set 2 4 6 8 10 12)))
12
3 4 5
Here
is
8.3 Sets
=>
=^
6)))
237
Program
none
8.5
(define none
(laitbda (pre i)
(letrec
((test
(leunbda (s)
(or (empty--set? s)
test)))
Again,
if
pred
is
a predicate and s
is
set,
the expression
((there-exists pred) s)
when there is at least one element in s for which pred is true. We can
define there-exists in terms of none using the fact that there is an element
of s satisfying pred only when it is not the case that none of the elements of
is
true
(define there-exists
(lambda (pred)
(Icuabda (s)
The
written as
Then
the simplifying rule of Section 8.2 can be used to give us the following
form of the
definition:
Progrfon 8.6
there-exists
(define there-exists
(lambda (pred)
(compose not (none pred))))
238
The procedure lor-all is called with the call structure ((lor-all pred)
s) and is true only when pred is true for all of the elements in s. We can
again express f or-all in terms of none
of the elements in s only
when
if
is
true for
all
pred
is
(define f or-all
(lambda (pred)
(lambda (s)
((none (lambda (x) (not (pred x)))) s))))
Once
Program
and the
f or-all
8.7
(define for-all
(leUDbda (pred)
We
called
can test for the sameness of objects or sets with a sameness procedure
set-equal.
We
define
set-equal so that
it
can be used to
obj2)
is
true
name set-equal?
is
if
when objl
is
same
the
passed an operand,
its
value
is
set-equal?
use set-equal in a
((set-equal objl)
as obj2.
instead of set-equal.
We
We
We
can
(define set-equal?
If
their
is
of T.
set,
Then
if
is
8.3 Sets
we use the
criterion of
On
sameness used
if
a subset of a set
a subset of
The
definition
239
Program
8.8
set-equal
(define set-equal
(lambda (objl)
(lambda (obj2)
(or (and ((neither set?) objl obj2)
(equal? objl obj2))
(and ((both set?) objl obj2)
of set-equal
is
We now
element of a given
by
s,
element that
define a procedure
set.
If
the object
is
true
when obj
make
s that
use of
it.
We
equal to obj.
is
want to
We
see
it
argument
the
simplifies
is
some
is
s.
an
denoted
We
have
of the programs
an element
in the set
is
member
of the set s
it
tests
is
equal to
whether
its
we wouldn't be able
say (lambda (s)
We
set
an element of
is
is
help us. If
is
whether there
whether an object
tests
is
(set-equal?
We'd have
to
then have
(define element
(lambda (obj)
(lambda (s)
element
8.2,
definition of
to be
(define element
(leunbda (obj)
We now see
240
is
We can
to be
Program
8.9
element
These steps
form.
obj G s
is
member
3 obj
of the set
s.
The
set-theoretic
relation
obj as a member,
Program
8.10
is
tested for
b.
definition of contains.
contains
(define contains
(lambda (set)
(lambda (obj)
((element obj) set))))
member
of si
si and s2 are
sets,
member of s2.
This subset relation is denoted by si C s2. For example, {a, c} C {a, b, c, d}.
We also say that a set si is a superset of s2 if s2 is a subset of si. The superset
relation is denoted by si D s2. Thus {a,b,c,d} D {a,c}. We first define the
set
si
is
a subset of a
set
s2
is
if
if
each
a superset of s2.
We
is
also a
8.3 Sets
241
Program
superset
8.11
(define superset
(lambda (si)
(laabda (s2)
((for-all (contains
Program
sD)
s2))))
subset
8.12
(define subset
(lambda (si)
(lambda (s2)
The number
of elements in a set
is
number
set
is itself
number
is 3,
2.
6, c,
d}
is
It is
its argument
we
use recursion on the elements of the set. The cardinal
set.
To do so,
number of the-empty-set is 0, which gives us our terminal condition. If the
set s is not empty, we pick out one element and compute the cardinal number
of the rest of the set. To get the cardinal number of s, we have to add 1 to
the cardinal number of the rest of the set. Here is the definition:
Program
8.13
ceirdinal
(define cardinal
(lambda (s)
(if (empty-set? s)
The
procedure to the
s.
is
We
typical of
242
Sets
and Relations
s,
it
Program
8.14
intersection
(define intersection
(leunbda (si s2)
(letrec
((helper
(lambda (si)
(if
(empty-set? si)
the-empty-set
(let ((elem (pick si)))
(if ((contains
s 2)
elem)
(helper si))))
The
and s2
is
we
is
not affected
The union
The
is
given in
is
b, c,
two
d} U
sets as
set si.
Program
definition
{b, d,
e}
{a,
b, c,
It
d, e}.
is
is
8.14.
all
of the elements
denoted by si U s2.
We
define a procedure
their union.
We
is
For example,
This
is
our terminal
The
difference
between the
sets si
{o,
b, c,
d}\
{b, d, e}
{a, c}.
We
is
and s2
It is
empty, the-empty-set
it is
is
adjoined to the difference between the rest of si and s2. This leads us
8.3 Sets
243
Program
8.15
union
(define union
((helper
(lambda (si)
(empty-set? si)
(if
s2
(let ((elem (pick si)))
(if (not ((contains s2)
elem))
(helper 5l))))
Program
8.16
difference
(define difference
((helper
(leunbda (si)
the-empty-set
(let ((elem (pick si)))
(if (not ((contains s2) elem))
(helper si))))
to the definition of
The
difference
in
Program
8.16.
striking.
This
common
procedural abstraction.
The
when
is
differ in
and pred
is
set si.
is
true.
structure
We call
Sets
We
call
an obvious candidate
what
for
set is returned
and Relations
is
And
they
We
use
base- set
244
and
difference
Program
8.17.)
Program
8.17
set-builder
(define set-builder
((helper
(lambda (s)
(if (empty-set? s)
base- set
(let ((elem (pick s)))
(if (pred elem)
helper)))
Procedure
base-set
pred
intersection
the-empty-set
(contains s2)
union
s2
difference
the-empty-set
Table 8.18
We
Base
sets
and predicates
for abstraction
ence using set-builder. Table 8.18 shows the values taken on by base-set
and pred
dences,
we
With
these correspon-
get
(define intersection
8.3 Seta
245
Program
(define
(
family-union
8.19
f aaily-union
lambda (s)
(if
(empty-set? s)
the-empty-set
(let ((elem (pick s)))
Program
family-intersection
8.20
(define family-intersection
(lambda (s)
(if
(empty-set? s)
the-empty-set
(letrec
((f am-int
(lambda (s)
(let ((elem (pick s)))
(empty-set? rest)
(if
elem
(intersection elem (feui-int rest))))))))
(f am-int
If
member
sets.
its
members
The union
U{{a.
s)))))
We
e}} =
S.
represent
{a,
6, c, d.
In a similar
all
e}.
We
define (in
parameter a
of the elements of
of the set S
symbolically by (JS.
it
its
members
elements of
set
is
called
For example,
s.
set S
S. It is
by P|{{a.6. c}, {a.c.e}. {a,6,c,/}} = {a, c}. We define (in Program 8.20) the procedure family-intersection that takes the parameter s,
is
illustrated
which
of
In
Why
246
all
is
a set
the sets in
Sets
sets,
s.
is
and Relations
in
Program
set-map
8.21
(define set-map
(lambda (proc s)
(if (empty-set? s)
the-empty-set
(let ((elem (pick s)))
the
same way
as
no computable
times
identity.
(see
Program
plus
Program
(see
7.10).
7.9)
and
for
how we
represent sets
cardinal and
For example,
s.
if
proc
is
set s.
It
when proc
is
the procedure
Suppose we have a
list
of objects
We
define
Program
list.
Thus we
in
Program
set-map
is
it
8.21.
into a set
define a procedure
list->set as
list->set
8.22
(define list->set
(lambda (Is)
(apply make-set Is)))
In a similar way,
and builds a
list
we can ask
list.
is
Program
8.23 shows
how
the
We
8.3 Sets
for
247
Program
set->list
8.23
(define set->list
(lambda (s)
(if (empty-set? s)
'()
(cons elen
set operations.
is
done
We
are
now ready
to
Exercises
Exercise 8.4
In this section,
terms of none. Show that we could have taken there-exists as the basic
in
Exercise 8.5:
in
it.
Similarly,
for-one
Consider the definition of the three-parameter procedure for-one, given below. Its
first
parameter
is
not-f ound-proc.
zero arguments,
parameter.
empty
It
its
s,
for
which pred
is
or
if
third parameter
is
is
invoked.
If s
is
invoked on that
(lambda (s)
(empty-set? s)
(not-found-proc)
(let ((v (pick s)))
(if (pred v)
(found-proc v)
(test ((residue v) s) )))))))
248
items in
contains an element
procedure fo\md-proc
(define for-one
test)))
a proce-
a procedure of
is
element.
(if
is
as
If s is
its
Here
is
an example of how
it
works:
((for-one
(lambda (x) (> x 7))
(lambda (v) (+ v 8))
(lambda
(make-set
()
"Not found"))
2 4 6
19 21 7))
there-exists and
se-
Exercise 8.6
we can
f or-all
superset
in this section,
as
contains))
We
set
all
We
is
We now
first
elements
defined.
is
a tagged
list
The
first
representation that
of those elements.
tag
is
we use
equal?
for a set of
is
We
We make
set? which
will
its argument is a pair and its car is that unique tag. For
the set {a,b, c} as the tagged list ("set" a b c). In
we
represent
example,
this first representation, we allow repeated elements in the lists. However, if
determine whether
in a list, that
and any other occurrences of that element in the list are ignored.
Thus the lists ("set" a b c) and ("set" a b a c b b) represent the same
set {a,b, c}. We divide the six basic definitions into two groups, the first
by the
list,
of which
is
249
Program
The shared
8.24
(lanbda (s)
(eq? s the-eapty-set)))
(define set?
(leiHbda (<urg)
(define pick
(Isjibda (s)
Random number
list
(see
in order to
The
definitions in
We
Program 8.25
is
of
we allow repetitions
make use of the procedure remove (see Program
reflect the fact that
in the repre4.6).
Here are some examples of how the procedures behave using our representation that allows repetitions of items in the
lists.
((element
'(baa)))
'a)
=>
=^
it
250
Seta
and Relations
Program
8.25
I)
(define residue
(lambda (elem)
(lambda (s)
(let ((Is (remove elem (cdr s))))
(cond
(define adjoin
(lambda (elem s)
(cons set-tag (cons elem (cdr s)))))
(union (make-set
112
3 4)
6))^
(make-set 3 4 4 5 6
12
(intersection (make-set
(make-set 3 4 4 5
(difference (make-set
(make-set
112
("set"
12344566)
3 3 4 5)
3 3
7))^
345)
("set"
4 5)
3 4 4 5 6 7))
=>
("set"
'
2)
(a b c))
=>
(list->set '(a
("set" 3 2
10)
d d))
d e))
=>
Another representation
for
set s is
list
("set" c d)
does not allow repetition of elements. The selector residue now has to remove
only the
first
occurrence of
its first
no
the object,
is
already an element of
if it is
its
not already a
member
of the
set. It
set.
adds the
Program
8.26
with no
repetitions.
Here are some examples of how some of the procedures defined in Section 8.3
look
when using
251
Program
The
8.26
(define residue
(la>bda (elea)
(laabda (s)
(let ((Is (reove-lst elem (cdr s))))
(cond
'
the-empty- set)
((niill? Is)
(define adjoin
(labda (el en s)
(cond
s)) s)
(union (aake-set
12
3)
(make-set
(intersection (aake-set
12
(difference (make-set
2 3)
all
its
4)) == ("set"
(aake-set 2
3)
first
is
4))
4))^
(make-set 2 3
"Which representation
ask.
tages.
1234)
("set" 2 3)
("set" 1)
its
advan-
residue does
it
has to
representation,
it
resentation,
to be
added
is
since
it
list.
The
there
first
involving no repetitions
lists
is
a trade-off
when choosing
We
have built into our universe, not only symbols, numbers, and booleans.
but any data for which equal? works, and that includes
examples using
lists.
Here
(make-set
=*
'(1 2)
2
'
("set" (2 3)
(union (make-set
'(2 3))
(1 2)
1
(make-set
'
(3 4)
2
1
(make-set 1 2 (make-set
=* ("set" ("set" 2 3)
252
Sets
and Relattons
2)
(1
2)
2)
(3 4))
(make-set
(make-set
("set"
some
lists.
(union (make-set
aire
3))
3
2)
4)))
("set" 3 4))
(family-union
(make-set
(make-set
=^
(make-set 2 3) (make-set
2)
("set"
12
4)))
3 4)
We have now seen another application of data abstraction in this development of the set data type. We defined all of the set operations using six
basic definitions, and only these six depend upon the specific representation
of the sets that we use. We then showed how to define these six using two
different representations of sets. The extensive use we made of currying in the
definitions of
many
made
example,
It
it
also enabled us
more
number
from
sets of
For
numbers, we can
apply (residue 0) to any such set of numbers and get the desired
also
easily to
result.
We
dures in set -builder. In the next section, we shall apply sets to a discussion
of functions and relations.
Exercises
Exercise 8.7
Use
this definition of
pick
to
implement
sets
with
lists
having repetitions:
(define pick
(Icu&bda (s)
on
sets that
Do
sets.
Exercise 8.8
in this section
number of sets
12
13
3 4)
4 5)
12
3 4 5)
253
(intersection
12
13
15
(ake-set
(ake-set
(ake-set
3 4)
4 5)
6 3
7))=^
("set"
3)
Abstract the structure of these two definitions to get a procedure from which
tinion and intersection can both be obtained by passing the procedural
symmetric-dillerence
Exercise 8.9:
Define the set procedure symmetric-difference that has two sets si and s2
as parameters
in si but not in s2 or in
s2 but not
in si.
For example,
(synaetric-dif ference
12
(ake-set
(ake-set
4 5)
3 4 5 6 7))
("set"
1267)
power-set
Exercise 8.10:
Define a set procedure power-set that has a set s as parameter and returns
the set consisting of
all
(power-set (ake-set
=*
subsets of
'a
is
Assume
that
power-set
For example,
'c))
'b
("set" ("set" a b c)
("set" a b) ("set" a c)
("set" b c)
("set" a)
Hint:
s.
is
("set" b)
("set" c)
("set"))
when an element
picked out.
select-by-cardinal
Exercise 8.11:
sets.
as its
with parameter
((select-by-cardinal 2)
(ake-set (ake-set
(ake-set
(aake-set 'a
'a)
'b
'c)
-^
254
Sets
and Relations
(ake-set
'b)
(ake-set
'a
'b
'b)))
("set" ("set" a b)
("set" b c))
'c)
8.5
pairs
uct of two sets are defined and use these ideas to develop the logical concepts
An
(x, y)
ordered pair
and
We
same.
is
We
is
significant; that
is,
the basic operations that apply to ordered pairs and then look at possible
There
constructor.
its
is
is
first
element
in the
a selector called op-2nd that returns the second element in the ordered pair.
Finally, there
y)
a constructor that
is
is
member. There
is
also a predicate
called
is
its
op? that
tests
whether
its
argument
is
an
ordered pair.
We now
We
lists,
and dotted
pairs.
Logicians usually start with sets and build other concepts from them. In our
first
representation,
pared to the
last
we show how
this
list
first is
quite complicated.
It
Comshows
senting ordered pairs. If you are not interested in the set theory development
of ordered pairs, you can skip over the next two paragraphs and go on to the
list
We
first
naive
first
sent the ordered pair (x,y) with the set {x,y}. However, there
^ y,
sets. We
if
by the
is
a problem:
then (x, y) 9^ (y, x), but {x, y} = {y, x} since order is immaterial in
can get around this difficulty by representing the ordered pair (x, y)
set
as long as X
is
which
is
y.
We
D {x,
x)
is
represented by the
(y,
y} of the two
member
sets.
is
it is
Similarly,
if
between Uii^)' i^' I/}} ^^^ flii^)' {^' y))- ^^ ^ ^^^ V ^^^ equal,
pick the first element of the ordered pair. It should be observed that the same
difference
255
Program
8.27
I)
(define nake-op
(lambda (i y)
(maOce-set (make-set i)
(make-set x y))))
(define op?
(lambda (set)
(and (set? set)
1)
1)
(family-union set))))))
(define op-lst
(lambda (op)
(pick (family-intersection op))))
(define op-2nd
(lambda (op)
(let ((fam-int (family-intersection op)
ordered pair
is
represented by {{z}, {x, y}}, {{z}, {y, z}}, and {{y, z}, {z}}.
in
terms of
sets,
procedures for ordered pairs are given in Program 8.27. Given the
first
element
X and the second element y of the ordered pair, the constructor maie-op
produces the ordered pair {{z}, {z,y}}. To understand the definition of op?,
observe that
it is
number
is
We
is
illustrated
number
of an ordered pair to be
{{a}, {a}}
{{^}}i so
its
cardinal
one.
There are other ways of representing ordered pairs that we can also
For example, we can
use.
Then we have
let
256
Seta
and Relations
is
Program
8.28.
Program
8.28
II)
(define make-op
(leuttbda (x y)
(list X y)))
(define op?
(lambda (Is)
(and (pair? Is)
(lambda (op)
(car op)))
(define op-2nd
(lambda (op)
(cadr op)))
Program
8.29
III)
(define make-op
(Izimbda (x y)
(cons X y)))
(define op?
(lambda (pr)
(pair? pr)))
(define op-lst
(lambda (op)
(car op)))
(define op-2nd
(lambda (op)
(cdr op)))
is,
as (cons x y).
definitions in
We
and
5*2 is
257
cartesian-product
Progrcmi 8.30
(define caurtesiam-product
the-empty-set
(let ((elem (pick si)))
(>
(( residue
(cartesian-product
two
sets {a,
6,
and
c}
{(a, d), (a, e), (6, d), (6, e), (c, d), (c, e)}
relation
from a
set
Y. The empty
is
set
is
first
following
is
and
element
a,
is
in
a relation from
is
of the relation
consisting of
all
pair in R. In our
The range
elements of
from
set of
is
if
to
is
that appear as
(make-op
1)
is
'c
1))
first
of the relation
of the
to Y:
The domain
defined in
Y is defined to be a subset
Y Thus the relation R is
to a set
is
relation
is
consisting of
elements of
A
with
For example,
if
is
members
258
Sets
and Relations
is
given by
Program
domain, range
8.31
(define domain
(laabda (rel)
(set-aap op-1st rel)))
(define rzmge
(lambda (rel)
(set -map op-2nd rel)))
(define is-older-than-relation
We
members bl and b2
op bl b2)
is
if
its
set to another.
all
pairs
We now
new
when we
((subrelation/lst is-older-than-relation)
relation
as their
enter
'torn)
the subrelation consisting of the two ordered pairs starting with tom
turned. See
in
Program
write
re-
is
8.32.
to a set
is
first
elements have
to
diff'erent
are already
f{x).
is
If
in
With
this
is
the
259
Program
subrelation/lst
8.32
(define subrelation/lst
(lambda (rel)
(lambda (arg)
((set-builder
(lambda (x) ((set-equal (op-lst i)) arg))
the-empty-set)
rel))))
Program
function?
8.33
(define function?
(lambda (rel)
(or (empty-set? rel)
function? that
tests
.}.
We now
whether a relation
is
nonempty,
(pick rel)
in rel. If the
1,
false
relation obtained by
until
is
number
first
Program
8.33.) If
is
repeated on the
is
The
a function. (See
is
greater than
value of a function
at
left
an element x
in the
domain of/
is
is
returned.
the second
el-
ement in the ordered pair in / that has x as its first element. In Program 8.34,
we define a procedure value that takes a function fun as its parameter and
returns a procedure that takes as its parameter an element arg in the domain
of
at airg.
1,
we introduced
as a data type having the constructor cons and the two selectors car
and cdr. Here we have developed sets as a data type having the constructor
adjoin and the two selectors pick and residue. Using these, we defined many
lists
We
sets.
We
used
lists in
260
Sets
several representations of
and Relations
sets.
Ordered pairs
selectors
Progrjun 8.34
value
(define value
(lambda (fun)
(Icu&bda (eirg)
op- 1st and op-2nd. These were used to define relations and functions on
sets. It is interesting to observe that if we start with sets as our bcisic data
type,
we can use
sets as
we did
lists.
and cdr
The empty
to be op-2nd.
list
()
We
is
of the procedures on
we have come
full circle.
lists in
terms of
sets, or
sets in
terms of
lists.
We
leave
lists
We
represented by the-empty-set.
it
clear
how powerful a
to other procedures
cedures.
We
All of this
is
lists
tool
we can proceed
to define
Thus
we can take
(),
it
we
y,
it is
in this
and develop
of functions and
chapter should
make
arguments
it is
Scheme.
Exercises
Exercise 8.12
In
fine op-lst
8.29,
we can
op-lst
as (de-
Redefine
all
of
the procedures in Programs 8.28 and 8.29 for which the simplifying rule
is
applicable.
In the following exercises, use the set operations developed in this chapter.
do
261
Exercise 8.13:
relation?
inverse of
a relation.
inverse-relation
Exercise 8.14:
The
is
an ordered pair
(a, b) is
inverse.
relation
and returns
a relation
is
Exercise 8.15:
function
is
its
The
inverse of
replaced by
its
its
argument a
inverse relation.
one-to-one?
called one-to-one
if its
inverse relation
is
is
make-relation
convenient way of defining a relation rel
Exercise 8.16:
is
to give
an arbitrary number
'(1 3)
2)
Exercise 8.17:
reflexive?
binary relation
is
on a
set
is
called reflexive
if
for each
x in S, the
Exercise 8.18:
symmetric?
i?
binary relation
make-relation.
on a
set
is
is
reflexive.
called
symmetric
if it is
equal as a set to
its
inverse relation. See Exercise 8.14. Define a predicate S3rmmetric? that tests
Exercise 8.19:
is
symmetric.
function- compose
Suppose that / and g are functions such that the range of g is a subset of
the domain of /. The composition of / with g is the function consisting of
all
ordered pairs (z, y) with x in the domain of g and y in the range of / and
for
(z, y)
f.
Define
262
of g
is
Sets
and Relations
Exercise 8.20:
R are
relation-compose
If
is
and
ordered pairs
(x, y)
with
the procedure
r.
Exercise 8.21:
transitive?
binary relation i? on a set S
with R'\s
a.
is
called transitive
if
the composition of
a relation rel
is
(trEuisitive?
(make-relation '(1 2)
(transitive?
(make-relation '(0 0)
(transitive?
(make-relation '(1 1)
Exercise 8.22:
'(1 3)
'(1 4)
'(2 3)
'(2 4)
'(1 1)
'(2 2)
'(3 3)
'(4 4)))
'(12)
'(3 2)
=>
=>
#t
#t
equivalence-relation?
reflexive,
'(3 4)))
is
equivalence-relation? that
tests
called
an equivalence relation
and
if it
is
an equivalence
8.21.
(equivalence-relation?
(make-relation '(0 0)
'(1 1)
'(2 2)
'(3 3)))
=>
#t
'(0 1)
'(1 0)
'(1 1)))
#t
'(0 1)
'(1 1)
'(2 2)))
=>
#f
(equivalence-relation?
(make-relation '(0 0)
(equivalence-relation?
(make-relation '(0 0)
263
Part 3
Managing State
What
is
change?
If
we think
Eating
you
left
full,
food supply, enriched the purse of the restaurant's proprietor, and depleted
your buying power. All of these are changes. The state of the world after you
left
Managing
means that
state
all
the effects of a
is
gramming
that
we have
we introduce a new
except that we access it
vector
is
like
list,
9,
with operations that use the elements' indices, which are nonnegative integers, instead of
first
rest of
we introduce
We
we use changing
of state to develop
in vectors. In
some
efficient
Chapter
11,
procedures
we strengthen
12,
lists
and
This leads to
local variables.
programming
In Chapter 13,
we use
object-
Using Vectors
9.1
Overview
We
plications
lists
we have had
disadvantage that
is
so far, lists
and
list
for
it
contains
1000 elements, and we want to know what the element with zero-based index
900
is.
is
3.7,
for us,
and we invoke (list-ref Is 900). But the computer is doing just as much
work to access the 900th element of the list for us. It would be nice to have a
data type in which we could store elements and look directly into the 900th
to store data.
We
see
random
access.
9.2 Vectors
In mathematics, a vector
to
1,
is
a function defined on a
its
index.
is
from
said to be the
mathematical representation of a
index
2, is (a, 6,
c).
The word
vector
is
0, b
with index
symbols,
lists,
elements
a, b,
and
c with
Scheme that
some given number. The
associates
1,
for
example, numbers,
and
Scheme
c,
representation of a vector
is
uses
#(a b
c).
a sharp symbol,
#,
enclosed in parentheses.
As with the other data types we have studied, we begin with certain basic
procedures in terms of which we define the rest of the procedures involving
vectors. The actual representation of the vectors and the basic procedures
will be defined in several ways after we develop the other procedures in a
representation-independent fashion. The first of our four basic procedures is
the predicate vector?, which tests whether its argument is a vector. The second one is the procedure vector-length, which takes a vector as its argument
and returns the number of elements in the vector.
The selector for vectors is called vector-ref It has the call structure
(vector-ref vec k), where vec is a vector and A; is a nonnegative integer
less than the length of vec. It returns the element in vec that has index k. To
illustrate the use of this selector, we define a procedure view (See Program 9.1
and Exercise 9.2.) that takes a vector and displays its external representation.
If vec is the vector with the elements 1, 2, 3, and 4, we have
.
The
index to be one
Thus we
locally define
highest-
less
displays in order the elements of vec, each, except for the last one, followed
by a space.
Thus the
desired output
is
obtained by
first
displaying "#(",
then invoking (loop 0) to display the elements of vec, and finally displaying
")" In our implementation,
expression
The
is
suppressed, so
we use
for vectors,
is
a curried
call structure
The operand size is a nonnegative integer that is the length of the vector
we are constructing. The generating procedure gen-proc is a procedure that
takes an index as
268
Using Vectors
its
Program
view
9.1
(define view
(lambda (vec)
(let ((highest- index (subl (vector-length vec))))
(begin
(display
"
")
(display "(")
(loop 0)
(display ")")))))
we
less
are constructing.
vector-generator returns a
The index
is
any integer
in the
than size.
it
if
(0
0)
#(123456)
[3]
(0
[4]
2 3 4)
(()
'())) 4))
())
[5]
[6]
(0
[7]
#(0
14
i))))
4 9)
9 16 25)
Later we shall give ways of representing vectors and defining these basic
procedures.
9.2 Vectors
We now
show how to
we need,
269
basic procedures.
The
first
one
is
Scheme procedure
and fills all of its
the
is
filled
If
value
not given,
is
all
of the
although this
(),
fill
we use
fill
to
we
building,
eire
argument
is
always the
fill
first
To accomplish
is
size
the value
the definition of a
We distinguish
surgs.
as its
is
If it is,
Here
is
Program
make-vector
9.2
(define nake-vector
(lanbda args
(let ((fill-value
(if (singleton-list? args)
'()
(cadr args))))
A
a
convenient
list
the
The
way
erating procedure
Program
list for
We
270
9.3.
consider a
i,
more
is
this
is
is
list
to start with
Is as
its
parameter.
Because list-rel
each index
Using Vectors
is
being created
list
is
(list-ref Is i)).
We
then get
Program
list->vector
9.3
(define li8t->vector
(lanbda (Is)
is
pro-
number of arguments is
The definition of vector is:
the
is
the
its
elements.
The
arbitrary,
vector
Progriin 9.4
(define vector
(laabda
surgs
(li8t->vector args)))
[1]
#(()
()
())
[2]
(view (li8t->vector
id
2 3
[3]
'
(1 2 3
(4 5 6))))
(4 5 6))
(a b (a b c))
[4]
(6 syabol 5)
The
length of a vector
is
fixed
when
it is
defined.
a vector vec of length k, and we find that we need a longer vector, say one of
length n, that has
new
vector
is
its first
We now
We say that
the
use vector-generator
vector.
9.2 Vectors
271
Program
vector-stretch
9.5
(define vector-stretch
(vector-ref vec i)
'()))))
If
a copy of vec.
is
Program
Thus we
is
the
same
vector-copy
as
shown
in
9.6.
Program
9.6
vector-copy
(define vector-copy
(lambda (vec)
elements changed.
We
Program
9.7
9.7.
vector-update
(define vector-update
val
We
this
272
Using Vectors
first
Program
list->vector
9.8
(define li8t->vector
(lambda (Is)
(let ((vec (ncJce-vector (length Is))))
(letrec
(convert
list
letrec expression in
vector-update
to give us a
new
vector
new-v
the
list.
is
is
all
list->vector
We make an
improvement
At that time, we
procedure
in the
shall
need
produce an
Suppose we have a vector vec and want to construct a new vector whose
elements are obtained by applying the procedure proc to the corresponding
elements of vec.
dure map.
We
Program
9.9
To accomplish
call
this,
vector-map
(define vector-map
(vector-length vec))))
9.2 Vectors
273
For example,
[1]
(11 12 13 14)
[2]
#(t #f #t)
[3]
(view (vector-map
(lambda (elem)
(vector 10 11 12 13)))
We
call
if all
of
its
numbers
as scalars.
is
the vector
(cai, ca2,
a scalar c
ccLn)-
by
Program
9.10
multiply-by-scalar
(define multiply-by-scalair
(lambda
(c vec)
We
define an analog to
to-both,
for
elem)) vec)))
Program
9.11
vector-apply-elementwise-to-both
(define vector-apply-elementwise-to-both
(lambda (proc)
(lambda (vecl vec2)
(let ((gen-proc
(lambda (i)
(proc (vector-ref vecl i)
The sum
274
Using Vectors
and vec2
of the
same length
is
the
vec2.
We
we
Program
9.12
its
operand.
vec+, vec*
The
[1]
is
illustrated by:
13
5 7 9)
(vector
97531)))
13
5 7 9)
(vector
97531)))
#(10 10 10 10 10)
[2]
(9 21 25 21 9)
Then we
When
vector-sum to
Program
set
up a
local recursion
more elements
to add.
We
0.
define
be:
vector-sum
9.13
(define vector-sum
(lambda (vec)
(let ((size (vector-length vec)))
(letrec
(
(helper
(lambda (i)
(if (= i size)
(+ (vector-ref vec i)
(helper 0)))))
In a similar way,
9.2 Vectors
we
define
275
Program
vector-product
9.14
(define vector-product
(lambda (vec)
(let ((size (vector-length vec)))
(letrec
((helper
(lambda (i)
(if (= i size)
1
(*
(helper 0)))))
13
(vector-product (vector
It
5 7 9))
13
^^
5 7 9))
25
945
last
very similar in structure, and that they are ideal candidates for abstraction.
we call proc. Then the definition of vector-accumulate is given in Program 9.15. We can now rewrite the
definitions of vector-sum and vector-product using vector-accumulate:
the operator applied in the alternative, which
+0))
We
we have not
But that
We
shown
in
is
just a recursion
9.16.
(vector->li8t (vector
Using Vectors
1))
Scheme proce-
Program
Then
2 3 4))
276
list
3 4))
=* (1 2 3 4)
=* (abc 3 4)
Program
9.15
vector-accumulate
(define vector-accumulate
(Isunbda (proc seed)
(lambda (vec)
(let ((size (vector-length vec)))
(letrec
((helper
(lambda (i)
(if (= i size)
seed
(proc (vector-ref vec i)
(helper 0))))))
Program
9.16
vector->list
we want
8.95, 12.00)
represent the
to
We
found
it
is
2 x $15.50
5 x $8.95
x $12.00
$111.75.
in the
two
and V
u and
is
is
the
number
ao^o
(&0)
t^i&i
&i)
o,n-ibn-i-
We
v of
already have a
procedure vec* that computes the vector whose elements are the products
where we use a more general version of compose that allows its second argument to be a procedure of arbitrarily many arguments. It is defined by
9.2 Vectors
277
(define compose
(laabda (f g)
(lambda args
(apply g args)))))
(f
Although
getting
this
is
In the process of
it.
it is
not an
efficient
way
of
procedure
first
we can
just
vectors
is
this process
is
(define dot-product
(let
(cond
((= i size) 0)
(loop 0)))))
An
even more
efficient
way
of
Program
Its
code
is
given in
9.17.
We
vectors
It is
we use
now time
in the
Since a vector
is
mathematically
characterized as a function from the index to the element with that index,
can
pair
first
is
the tag
is
The
we
car of the
"vector".
The
whose cdr
278
is
Using Vectors
is
is
Program
9.17
dot-product
(letrec
((loop
(lambda (i ace)
(= i size)
(if
ace
(loop (addl i)
(+ ace
(*
(vector--ref vecl i)
(vector--ref vec2 i))))))))
(loop
0)))))
With
and vector-length,
9.18.
Program
in
Program
We make
these conventions,
we
the convention
define
vector?
vector?, vector-length
9.18
(define vector?
(lambda (arg)
(and (pair? arg)
(define vector-length
(lambda (vec)
(car (cdr vec))))
The
parameter.
as
its
its
It
size
list
as a representation of a vector.
we develop.
in Program
We
in place of
This
is
in
Program
is
definitions
9.19.
279
Program
9.19
(define vector-ref
(lambda (vec
i)
(define vector-generator
(laaibda (gen-proc)
(laabda (size)
(cons vector-tag (cons size gen-proc)))))
Program
9.20
II
(define vector-ref
(lambda (vec
i)
i )))
(define vector-generator
(lambda (gen-proc)
(lambda (size)
(cons vector-tag
(cons size
(letrec
((loop (lambda (i)
(cond
((=
size)
'())
(loop (addl
.))))))))
(loop 3)))))))
(
of the results.
We now
have
("vector"
[2]
list
With
280
Ustng Vectors
random access.
random access to the
It is
elements, for
to cdr
down
the
list
until
we
list
we have
index, and the
computer resources used in this cdring increase with the index. It may appear
as though the representation of the vector using a procedure that assigns an
element to each index gives true random access to the elements, but consider
the following situation where vectors are represented as procedures:
(let ((a (make-vector 4 5)))
(let ((b (vector-update a
(let
10)))
(vector-ref d 0)))))
compute (vector-ref d 0), we first invoke the procedure representing the vector d with argument
to find that it invokes the procedure
representing the vector c with argument 0, which in turn invokes the procedure representing b with argument 0, which in turn invokes the procedure
representing a with argument 0, which returns the value 5. If we had asked
for (vector-ref d 3), the value 30 would have been returned with just the
In order to
one procedure invocation. Thus, the resources needed to access the different
elements of d depend upon the indices of the elements.
We
as a
list
The
it.
The
third representation
we
#, is
discuss
Scheme
displaying vectors
with the procedure view. Thus the vector with elements 20, 30, 40, and 50
written as #(20 30 40 50). This
Like
evaluates to a vector.
when we
lists,
we
is
is
vector constants
must be quoted,
so that
get
'#(10 u (+ 2 3) "Mary")
[1]
#(10 u (+ 2 3) "Mary")
[2]
[3]
#(10 20 30 40 50)
vector-length, and vector-ref are provided by Scheme. Our fourth basic procedure, vector-generator, is not in
Scheme, but we can use the two Scheme procedures make-vector and vector-
The
set
to define
it.
We
281
list
The
original vector
vec
has
still
its
original elements,
and only the copy has the element with index k changed to c. With the procewe invoke (vector-set vec k c) and we do not create
dure vector-set
a new vector, but instead we change the element with index k in vec to have
,
the value
new
c.
vector. Instead,
an invocation of vector-set!
value since
it
is
is
is
is
in vec.
not specified, so
with obj.
in vec is replaced
structure
Its call
is,
is
a side
an exclamation mark,
exclamation mark
We
bang."
is
at the
As
effect.
such,
it
is
It is
is
returned by
others,
we
shall
[1]
(define vl (vector
[2]
vl
#(0
2 4 6 8)
[3]
(vector-set! vl 2 5)
[4]
vl
#(0 2
2 4 6 8))
5 6 8)
!,
basic constructor
first
constructs a
vector vec of the desired length size (> 0), with unspecified elements.
it
size,
it
from
to size.
less
Then
than
proc applied
to
i.
When
all
of
its
entries changed,
and
its
Using Vectors
since the
282
For each i
is
if
is
The
expression.
The
is
the
first
is
the vector
vec
is
structure of this
changed by side
Program
9.21
vector-generator
(define vector-generat or
(lambda (gen-proc)
(lambda (size)
(let ((vec (make--vector size)))
(letrec
((loop (leunbda (i)
(if
(< i size)
(begin
(vector-set
vec
(gen--proc i))
vec))))
When we
use vector-set
it
,
!
we
are interested in
returns. If
we do want
its
side effects,
and we do
Program
9.22
vector-update!
(define vector-update!
(lambda (vec
i c)
(vector-set! vec i c)
vec))
When we
that
we would
it
283
can now do
using vector-set
it
length as the
list
We
first
Program
Program
list,
list.
We
same
changing
The code
is
9.23.
list->vector
9.23
(define list->vector
(lambda (Is)
(let ((vec (make-vector (length Is))))
(letrec
((convert
(lambda (Is
(if
i)
(begin
(vector-!set! vec i (car Is))
(addl i)))))))
(convert Is 0))
vec)))
!
In this program,
we again
vector
is
see that
vector-set
changing an element
is
in a vector.
The mutation
When
mutation
is
introduced,
vec
is
of the
When
the
returned.
we must adopt a
different point of
view about
programming, an object
object
is
is
vector a, which
is
(vector
2 4 6),
and
let
In functional
If
we
start
b be (vector-update a
we have
with a
1
5),
(vies a)
(newline)
(view b)
(newline)))
5)))
(2 4 6)
284
(2
On
6)
Using Vectors
if
a,
and we have
[2]
5)))
(writeln a)
(writeln b)))
#(2
5 6)
#(2 5 6)
In the
let
first
determined by
expression in [2]
elements.
its
let
is
is
in
is
determined by
certain state variables (in our example, they are the elements of the vector).
we know the
If
state of
an object, we know
its
When
using mutators, one must be conscious of the fact that each object has a
certain state
in state
in
mutators
in
Chapter 11
comparing programming
with programming
We next
We
vector-update
using the mutator vector-update
imperative style
To do
so,
We
procedures or as
first
lists).
is
(this
The swapping
is
and
is
is
even).
The
1.
odd) or until
is
and
indices i
decreased by
returned.
The
greater than
is
resulting vector
is
its
indexl and index2 as parameters and returns a copy of vec that has
vector-reverse
We now
is
in
Program
The code
for
9.24.
to
is
i starts at 0,
j (this
its
increased by
(either as tagged
its
285
Program
9.24
(letrec
((switch
(lambda (v
i j)
(>= i j)
(if
(switch (swapv
(addl i)
(subl j)))))))
(switch vec
Program
i j)
9.25
(define swap-maker
(lambda (vec)
(lambda (indexl index2)
(let ((temp (vector-ref vec indexl)))
(vector-update
(vector-update vec indexl (vector-ref vec index2))
index2
temp)))))
Now vector-update
its
It
returns a
is
new
the swap.
We
[1]
12 3 4 5)))
(let ((b (vector-reverse a)))
(view a)
(view b)
#(12
(newline)
(newline)))
3 4 5)
#(5 4 3 2 1)
We now
Program
vector-reverse!.
We
are able to
make
a few optimizations in the program, taking advantage of the fact that the
vectors have state that changes with invocations of the mutators.
286
Using Vectors
Now we
do not have to pass the vector vec as an argument to the local procedure
switch and switch does not have to return a value. We can also define the
local procedure
switch.
Program
This
9.27) returns a
its
is
faster running,
We
[2]
more
efficient
programs.
12
3 4 5)))
(writeln a)
(writeln b)))
#(5 4 3 2
1)
(5 4 3 2
1)
itself,
whereas
in the
Program
9.26
vector-reverse
(imperative version)
(define vector-reverse!
(launbda (vec)
(letrec
((switch (lambda (i j)
(if
j)
(begin
(swapv!
(switch
j)
vec)))
287
Program
9.27
(define swap-maker
(lambda (vec)
(lambda (indexl index2)
(let ((temp (vector-ref vec indexl)))
(vector-update
(vector-update! vec indexl (vector-ref vec index2))
index2
temp)))))
of
to be a set
Then when we
update
we open the
lid,
ball.
is
its
random
way
is
the same.
is
as
virtually
in the vector
contents are.
in the box,
We
vector-
use
is,
all
do with
Random
ac-
Sequential access in
lists
Thus we
see that
In the
first
to implementing vectors.
When we want
to
which constructs a new vector that has the new element, and the original
vector
is left
is
called func-
to vectors,
288
Using Vectors
random
us
if
must
Exercises
successive-powers
Define a procedure successive-powers that constructs a vector of length n
whose entries are the successive powers of the number base. The element with
index
is the 0th power of base. The procedure should be curried so that its
Exercise 9.1:
parameter
first
is
is
((successive-powers 2) 8)
((successive-powers 3) 5)
^^
^^
#(1 2 4 8 16 32 64 128)
#(1 3 9 27 81)
Exercise 9.2
view
vector-view
defined a procedure view when we used the procedural representation of
Exercise 9.3:
We
a vector to display the vector in the notation using a sharp sign followed by a
list
that
in
it
like
view, except
commas
9.2.
as used
With
all
similar program,
set-view can
Exercise 9.4
Let vl be the vector (vector
What
12
3 4)
and
let
v2 be (vector-copy vl).
289
b.
c.
What
Exercise 9.5:
The
vector-linear-search.
as
its
same
is
the
is
npradlbs)
(vector-linear-search '#(g
(vector-linear-search '#(29 13 96 -5 24 11
Exercise 9.6:
vector-
'a)
-15
It
^^
program
is
on:
4
2)
=^
11)
vector-append, vector-reverse
9.4 Matrices
We
have used
lists
and vectors
to store data. In
zero
this
way
starting with
We often use
a sequential organization
Many
times a table
in a telephone
is
is
way
The data
a phone number.
If
we take the
first
and
in general, the
nth entries
can be located
if
we
in all
we
row
and the zero-based index of the column. Thus in our table, "3314 Valley Dr."
is
matrix
is
1.
first
being the zero-based row index and the second being the zero-based column
index. In our discussion,
index
290
Using Vectors
we
refer to the
If
having row
m rows and n
"2117
"Jones, John"
M.
"Jones,
S."
W."
"Jose, Michael
"Joslin,
Figure 9.28
columns, we
Joan
P."
Plum
"412-8421"
St."
"424-7773"
"421-0035"
"412-5531"
call it
"m by n
an
if
matrix." This
is
is
is
Unlike vectors, matrices are not a Scheme data type, so we have to decide
upon a representation
in
for matrices,
We
number
number
We
of columns, respectively.
also
where mat
integers.
It
is
if
write
[1]
[2] (A-ref
"424-7773"
[3]
2)
(A-ref 2 1)
We
it
matrix-generator, and
it
is
an analog of vector-generator.
has the
We
call
call structure
where nrows and ncols are the number of rows and columns, respectively, of
the matrix
we
are constructing.
takes as
ments two indices and produces the element with those indices
its
in the
argu-
matrix
being constructed.
9.4 Matrices
291
We now
decide
defining an
how
There are
x n matrix A.
to represent a matrix.
we look
Each of the
x n elements in A.
of representing
at a concrete
is
as a vector
we
in A,
are
and
rows contains
example
and elements of A.
first
It will
be clearer
A=
Figure 9.29
We
3 x 4 matrix
This matrix, A,
has three rows and four columns. There are two ways of writing the elements
of a matrix sequentially, both of which are used in practice.
One
to write
is
the rows one after the other, to get the sequence of elements
523714058312
This way
one
is
called
is
sequence of elements
518243301752
This way of writing the elements
is
called
We
arbitrarily
Now
that
we
are agreed on
where one row ends and the next begins. In our example, there are
in all 12
Since
number
put
it
4,
at
a vector.
which
tells
us the
(vector
292
We
we can
Using Vectors
523714058312
4)
to
in
Program
9.30
num-cols
(define num-cols
(lambda (mat)
(let ((size (subl (vector- length mat))))
have
it
in this vector.
matrix A? Here
in the
It
is
and the
element
last
is
We
4.
last
Now
we
if
Thus
that group.
we
indices,
is
in the
is
in the
see that
divided by
Now
index
4,
(1
In general, v/e
is
is
is
3 rows.
elements in
2.
We
the quotient
We find
2.
1
4)
-I-
is
by
4,
represent an
the
same
having row
its
which
is
the
2.
mxn
is
mn+1
number
as the
elements of the matrix are enumerated in row major order, making up the
mn
as
We
elements.
shown
in
by
6.
mat, which
collect the
row index
and
the vector
we remove the
4.
let's reverse
left,
If
it
is
Thus
4.
What
The
first
Program
we have
to do
is
To
get the
We now
number of rows
define
of the matrix,
matrix-rel that has the matrix mat cis its parameter and
its parameters the row index i and the column
index
and
it
the element in the vector representation of the matrix, we must multiply the
9.4 Matrices
293
Progrfon 9.31
num-roHS
(define nmn-rows
(leunbda (mat)
row index
Program
j.
This gives
in the
us:
matrix-ref
9.32
(define matrix-ref
(lambda (mat)
(let ((ncols (num-cols mat)))
(lambda (i j)
(vector-ref mat (+ (*
ncols) j))))))
Exercise
Exercise 9.7
The
selector
indices i
and
definition so that
We now
is
it
contains such a
out of range.
Rewrite the
test.
We
first
procedure of one argument that generates the vector representing the matrix.
If
we
is
is
when k
is
divided by ncols,
when k
is
of the matrix.
294
Using Vectors
contains
and
its
in the matrix.
(lambda (k)
(gen-proc (quotient k ncols) (remainder k ncols)))
The length
of
Progrsan 9.33
We
is
matrix-generator
(define matrix-generator
(lambda (gen-proc)
(lambda (k)
(if
(< k size)
(remainder k ncols))
ncols)))
((vector-generator vec-gen-proc)
(addl size)))))))
all
of
its
elements zero
be vectors.
We
to select a
It is
convenient to curry the procedures row-of and column-of. To get the row of
the matrix mat with zero-based index
to get its
i,
9.4 Matrices
295
Program
row-of
9.34
(define row-of
(lanbda (aat)
(let ((mat-ref (natrix-ref mat))
(lambda (i)
(let ((gen-proc (lambda (j)
(mat-ref
j))))
and
Program
column-of
9.35
(define column-of
(lambda (mat)
(let ((mat-ref (matrix-ref mat))
(lambda (j)
(let ((gen-proc (lambda (i) (mat-ref
j))))
Figure 9.36
The
The transpose
transpose of an
x n matrix
.4 is
an n x
in
matrix whose
Figure 9.29
is
the
4x3
matrix
To
296
Using Vectors
Program
9.37
matrix-treinspose
(define matrix-transpose
(lambda (mat)
(let ((mat-ref (matrix-ref mat))
(mat-ref
i))))
((matrix-generator gen-proc)
(num-cols mat)
The elements
in
Scheme.
is,
are
of columns),
we can
define the
by
a,
scalar
and
size
sum A + B
to he the matrix
are the
if
(number)
of
c,
and B.
whose elements
Similarly,
we can
is
It is
also possible to define a useful multiplication rule for certain pairs of matrices.
It is
not customary to define the product to be the matrix whose elements are
example
A
and
W,
steel, plastic,
and
following
normally used.
X,
and
Z, at
each of two
sites,
W uses 4 units
uses 5 units of
The
2 units of rubber.
Product
To
sites,
we
set
making one
Units Used
Steel
Plastic
Rubber
W
Z
Site
/
Site
Steel
unit of each
Plastic
Rubber
$8
$7
$4
$5
$5
$4
at Site R.
We multiply
site
9.4 Matrices
297
and add these products. This is the dot product of the third row of the Units
Used matrix and the first column of the Cost Per Unit matrix. The result is
4 $8 + 3 $4 + 1 $5 = $49. We compute the cost of making a unit of each
sites
Site
$50
$46
$58
$53
$49
$47
$54
$54
Z
From
and
is a.n
mX
ith
is
as the
number
row vector
is
computing
their
product
an n x k matrix, then
their
product
m X n matrix and B
k matrix.
We
AB
AB
is:
if
is ein
of the
have developed the tools that enable us to translate this rule directly
AB
two matrices, they must be compatible, which means that the number of
columns of
A
A
this
Site
(define matrix-product
(Isunbda (mat-a mat-b)
(lambda (i j)
(dot-product (a-roH
i)
(b-col j)))))
((matrix-generator gen-proc)
(num-roBs mat-a) (num-cols mat-b))))))
This way of defining matrix-product follows directly from the rule describing matrix multiplication, but
it is
it.
Before actu-
We
sum
directly
from the
matrices without building the row and column vectors. Each element in the
ith
row of
second index
298
Using Vectors
has
j.
first
index
Thus the
i,
ith
row of
in the
jth column of
Oi^Oi
cii,i>
>
has
Oi,n-i>
Program
matrix-product
9.38
(define matrix-product
(if
(error "matrix-product:"
"The matrices are not compatible.")
(let
(
(gen-proc
(lambda (i j)
(letrec
((loop
(lambda (r ace)
(if
ncols-a)
(= r
ace
(loop (addl r)
(+ ace
(*
(a-ref i r)
(b-ref r j))))))))
(loop
0)))))
((matrix-generator gen-proc)
(num-roHS mat-a) (num-eols mat-b)))))))
of
.
.
fen-ij-
Thus
the dot product of the ith row and jth column, we must add
of the form ai^rKj where r takes
gram
integer values
we redefine matrix-product to do
and include a test for compatibility.
9.38,
directly
So
all
If
products
to
far this
form
n 1. In Prosummation of products
from
this
all
to
similar to vector-set!.
We
we use a
all
of the
can introduce a
When we
do
so,
the
matrix must be considered as having state with the state variables the
ele-
ments
in the matrix,
the matrix.
It
has the
is
where mat
9.4 Matrices
is
299
Program
matrix-set
9.39
(define matrix-set!
(lambda (mat)
(let ((ncols (nvim-cols mat )))
(lambda (i
obj)
(vector-set
column-index
from Figure
is
we have
9.28,
[4]
(define A-set
[5]
(A-set! 2
[6]
(A-ref 2
(matrix-set! A))
1)
is
In
two-dimensional arrays.
of vectors
We
called one-
and
is
random
is
carried out in a
Exercises
matrix
Define a procedure matrix that takes two arguments, m and n, and returns a
procedure that takes as its m x n arguments the elements of the mxn matrix
Exercise 9.8:
it
creates.
(Hint:
3 4)
5 2 3 7
14
8
300
Using Vectors
12)
Exercise 9.9:
mat+
returns their
the
same number
bij is
i,j
of columns. If aij
the element oi
is aij
bij
with indices
the
and
of rows
with indices
i,j,
arguments and
as
same number
the element of
is
A+B
i,j,
and
and
with indices
Exercise 9.10:
matrix-multiply-by-scalar
Define a procedure matrix-multiply-by-scalar that takes as arguments a
number c and a matrix A and returns the matrix cA, which has as elements
c times the corresponding elements of A.
matrix-view
Define a procedure matrix-view that takes an tti x n matrix as its argument
and prints the matrix in the format shown below. If m is the matrix given in
Figure 9.29 an invocation of (matrix-view m) should print
Exercise 9.11:
14
8
7
5
12
Next, include a tag matrix-tag and generalize the procedure view to display a vector,
set,
its
argument.
(See
Exercise 9.3)
Exercise 9.12:
elements of a
matrix-set
and matrix-generator.
Vector of vectors
n matrix can also be represented as a vector of length
Exercise 9.13:
An
mx
is
i is
m in which the
-2
-3
-1
(vector (vector 2
-3)
(vector 4 -2 -1))
For this representation of matrices, define the procedures niim-rows, numcols, matrix-ref, matrix-set!, and matrix-generator.
9.4 Matrices
301
Exercise 9.14
mn + l
element
and
k,
a,jfc,
where
0, 1,
,
.
We
rrin
for
1,
m x n matrix as a vector of
in a three-dimensional array
f
an
2, 3
is
mi 1,
is
m2 1, and ^ =
of length mi m2 ma
0, 1,
as a vector
A
.
0, 1,
.
.
i,
j,
ma 1.
2. The integer
we say that A is
-I-
more completely, and define the procedures sizedim-1, size-dim-2, and size-dim-S that are the analogs of num-rows and
num-cols and return the values mi, m2, and ma, respectively. Also define the
procedures array-rel, eoray-set! and array-generator, which are analogs
the vector representation
302
Using Vectors
10
10.1
Overview
The
to put
list
them
in
some
The
ing the
list.
the
list
lists
and
In this chapter,
vectors.
We
list is
is
specified
called sort-
called searching
we develop routines
for sorting
some
specified conditions.
10.2 Sorting
We
It is
more convenient
many
some
test
We
if
many
shall look at
Our first sorting technique is called an insertion sort. Suppose we are given
a nonempty list Is of numbers that are not ordered and that we wish to rearrange to be in increasing order.
If
the
we
list
We
first
list
contains at least
list is
if
we
recursively
Program
insertsort
10.1
(define insertsort
(lambda (Is)
(if (singleton-list? Is)
Is
(ins ertsort (cdr Is))))))
Program
insert
10.2
(define insert
(lambda (a Is)
(cond
'
()))
(cons a Is))
but the
sert
first
its
number a
inserts a
correct position in
this insertion,
list
containing
all
we afterward
list, all
define a procedure
list
Program
Is.
insert that
Program
10.1
insert.
is
is
is
is
built.
When
finally
is
list
Then each
insertions that has been waiting in the return table can be evaluated,
final sorted list is built up.
routine sorts a
When we
(10)
is
Is
is
list
of numbers.
We
start
how
of the
and the
with the
list
(50 40 30 20 10).
returned,
in the
return table are evaluated with sorted sublists as their second arguments.
We also write
an
304
Figure 10.3
Return table
for
insertsort
The value it
returns is unspecified, as is the case with many mutators. It is more convenient
to insert the numbers to the left instead of to the right when using vectors. Our
sort of the vector #(60 50 30 40 10 20) proceeds as shown in Figure 10.4.
At each stage, we can picture the process as removing the next item to be
inserted and shifting those before it to the right until we come to the place
that vector into one with the
as desired.
The
that
We
sort
is
elements to the
all
We
assume
left
then save the element with index k in a variable val, freeing up the kth
position so that
we can
shift into
it.
is
then inserted
it
procedure vector-insertsort
is first
to be inserted.
insert
to
The
sorted,
all
k+ 1
encountered.
To do
is
sortloop
calls the
first
element
procedure vector-
Each time
it is
called,
and vector-insert!
is
and
since that
local procedure
do the insertion
1,
its left
first
k elements.
Now
are in the correct order. This insertion process continues until the index
all
of the elements
in the if expression
in
Program
10.5.
10.2.1 Sorting
305
#(60 50 30 40 10 20)
Insert 50
(60
30 40 10 20)
#(50 60 30 40 10 20)
Insert 30
#(50 60
#(50
#(
40 10 20)
60 40 10 20)
50 60 40 10 20)
#(30 50 60 40 10 20)
Insert 40
#(30 50 60
#(30 50
#(30
10 20)
60 10 20)
50 60 10 20)
#(30 40 50 60 10 20)
Insert 10
#(30 40 50 60
#(30 40 50
#(30 40
#(30
#(
20)
60 20)
50 60 20)
40 50 60 20)
30 40 50 60 20)
#(10 30 40 50 60 20)
Insert 20
#(10 30 40 50 60
#(10 30 40 50
#(10 30 40
#(10 30
#(10
60)
50 60)
40 50 60)
30 40 50 60)
#(10 20 30 40 50 60)
Figure 10.4
Program
10.5
vector-insertsort!
(define vector-insertsort!
(laubda (v)
(let ((size (vector-length v)))
(begin
(vector-insert! k v)
(sortloop 1)))))
306
is
applied with
with indices
less
first
It inserts
index k into the correct place in the sorted part, so that those elements with
indices less than k
If it is called
are
with index
local procedure
called with
having index
m 1.
If
is
if
is
it
sorted.
Here
is
how vector-insert!
lets
as argument,
val
On
k,
insert -h
some index m
now
is less
k.
The
When insert-h
is
it
than comp, we
moved up
k.
works.
still
to have index m,
and insert-h
is
called
to
invoked,
Program
10.6
vector-insert!
(define vector-insert
(lambda (k vec)
(let ((val (vector--ref vec k)))
(letrec ((insert--h
(leunbda (m)
(if
(zero ? m)
(vector-set! vec
v&l)
(begin
(vector-set
vec m comp)
7ec
ffl
val)))))))
(insert -hk)))))
Throughout
this definition,
we used the
fact that
effect.
vector-set
is
When a vector
a mutation
v
is
passed
10.2.1 Sorting
S07
This
sorted.
is
we want a procedure
list
and the
original
not affected.
list is
copy of that vector but leave the original vector unaffected, we can use the
following procedure, vector-insertsort:
(define vector-insertsort
(lambda (vec)
(let
(vector-insertsort
v)
v)))
Here
is
[1]
[2]
(insertsort niimlist)
(10 20 30 40 50 60)
[3]
numlist
(60 50 40 30 20 10)
[4]
[5]
#(10 20 30 40 50 60)
[6]
numvec
#(60 50 40 30 20 10)
[7]
(vector-insertsort! numvec)
[8]
numvec
#(10 20 30 40 50 60)
We
its efficiency
list
is
n
at
done on a
list
list
of two numbers,
most l-|-2
+ 3+--- + (n
1)
= n[n
l)/2. This
worst possible situation, in which one has to go to the end of the sorted
in each case to
case in the
308
in general,
list
we would have
list
insert the
is
n{n
this
comparison
If
in insertion sort
is
the
0{n^), we
list is
call
alreeidy
in
n comparisons
are required.
10.2.2 Mergesort
The
We
list
number
considerably, so that a
it
list
list
is
a quadratic method
or vector of
n elements.
this
list
list
list
into a
list
(2
members
34 123
2 1), the
22
is still
3 3 4)
is
correctly ordered.
merged
is
(1 2 3)
(1)).
(2)
many
to give half as
this list
Then each
of
each of
the original
sublists,
list,
at
is
is
3 3 4)),
if
is
which
step
first
((11222
list.
is
sorted.
adds the adjective natural to the name mergesort. Another grouping method,
which leads to the procedure called mergesort without the adjective natural
is
the following.
element in each
((2)
(3)
sorted,
(4)
We group
sublist.
(1)
(2)
Thus
(3)
in the
(2)
list
so that there
initial
is
one
grouping yields
(1 4)
is
(2 3)
309
Program
make-groups
10.7
(lambda (Is)
(cond
'())
((null'' Is)
(list Is))
(c adr Is)
a)
Then
(1 2)).
successive sorted
((11222334)).
mergesort procedure
The
first
are
lists
is left
merged
((12
to give
The development
3 4)
is
of numbers, Is, as
its
If
Is
is
define a procedure
we
In order to
sublists,
and
() is returned.
is
consisting of the Is
if
we
let
itself.
the second
singleton
number
list
in Is,
of groups
is
(cdr
first
first
On
the
first
number
sublist in
in
Is
is
greater than
(make-groups Is)
number
if
the
it
must be added
result.
in gps.
(cdr gps)).
We
Thus the
is
group alrecidy
Program
If
then the
in not greater
We
list
(maie-groups Is).
gps))
Thus the
is
if
gps denote (make-groups (cdx Is)), there are two cases to consider
in order to get
first
as an exercise.
(12
result
is
first
in
Is
to the
(cau:
in
10.7.
310
Program
pair-merge
10.8
(define pair-nerge
(lambda (sublists)
(cond
merge has
as
its
list
is
list
To do
the mergesort,
is
We test
for
list
whether the
list is
applies
pair-merge
list
contains
parameter Is a
list
of
It
first
its
in largest possible
one
sublist.
Program
10.9
nat -mergesort.
Program
10.9
nat-mergesort
(define nat-mergesort
(lambda (Is)
(if (null?
]-S)
'()
gps)
To
10.2.2 Sorting
nat-mergesort procedure
is
consider a worst
311
case in which
them
of
list
list,
lists,
in
is
number
On
The question we must first answer is: "How many times can we divide
a number n by 2, rounding up to the next higher integer each time, until
we reach 1?" For example, if we start with seven numbers, the first pass of
pairs.
This
sublists.
is
rounding up to
4,
we divide 4 by
we divide 2 by
corresponding to the
What we have
asked
"What
is:
is
2*^
> n?"
if
n =
list is
at
statement logj n
sorted
then 2^
k.
We
a whole number.
m numbers,
at
most
together contain
ceiling
In
the
number
is
not
merging two
lists
n numbers,
to the
if all
of the sublists
we make at most
|log2 n] passes through the list and each pass needs at most n comparisons,
we have a total of at most npogjn] comparisons. Thus nat-mergesort is
pass of sort through the
will never
list
exceed n.
Since
example,
The
in
in
list
It
in vectors,
parts.
is
We
>,
and replace
maie-groups by rel.
> in the
into
An
numbers
of
we look
at such a version.
The
size,
recursive
iterative sorting
with
initial
value
1.
From the group size, we determine the end points of the groups. Then
we merge successive pairs of groups, with the usual proviso that if there is
an odd number of groups, one is left over after the merging. After the merge
phase, we double the group size and repeat the process. This continues until
312
Program 10.10
vector-merge'
(define vector-merge!
(launbda (newvec vec)
((mergeloop
(lambda (left right i)
(cond
(begin
(vector-set! newvec
(vector-set
(vector-set
is
the
same
initial
group
sort
an ordinary
is
,
!
which merges
two adjacent groups in a vector vec. Suppose that the group in vec with indices from left up to, but not including, top-left and the group with indices
from right (usually the same as top-left) up to, but not including, top-
Program
We now
in
sorted.
10.10.
its
!,
given
parameter. Since
another vector, we must always have another vector into which to carry out
10.2.2 Sorting
313
Program
vector-mergesort
10.11
(define vector-nergesort
(lanbda (vecl)
(let ((vec-size (vector-length vecl))
(let ((adjust (lambda (k)
(min k vec-size)))
(merge-pass
(lambda (group-size count)
(if (> group-size maix-index)
(vector-change! vecl
mzix-index vec2))
(letrec
((group-ends
(lambda (left top-left right top-right)
(if
(begin
(merge! left top-left right top-right)
(let ((new-right (+ top-right group-size)))
(group-ends
top-right
(adjust new-right)
new-right
(adjust (+ new-right group-size)))))))))
(group-ends
(adjust group-size)
(merge-pass
1))))))
this merge.
the vector,
into
we make a second
On
the
first
On
314
is
pass
1,
and
its
is
set to 1.
each successive merging pass through the vector, two adjacent groups are
Program
10.12
vector-change!
(define vector-change!
(lambda (vecl
k vec2)
(<= i k)
(begin
(vector-set
The end
of the local procedure group-ends; these are left, top-left, right, and
right
We
the
is
get
left
is
the
left
left
group, and
enough
group-size, top-left can exceed the length of the vector. In order to avoid
we use the local procedure adjust, which limits the size of its argument
to be at most the length of the vector vecl. The value of right is obtained
by adding group-size to left. And finally, we get top-right by adjusting
the sum of right and group-size. The mutator vector-merge! is then
invoked with these parameters to merge the two adjacent groups, and the
pass through the vector is made by repeated invocations of group- ends to
determine the successive pairs of groups. When a pass is completed, mergepass is invoked with the next group-size and count. Finally, when groupsize reaches the length of the vector, there is only one group and the vector
this,
is
Sorted.
If it
is
mutator vector-change!
of
is
are given in
10.12, respectively.
and k
10.2.2 Sorting
it
list
of the
same
This vector
It is
list
315
since
iterative.
it is
10.2.3 Quicksort
There
is
When
called quicksort.
is
0{nlogn)
sorted,
it is
like
lists
or in vectors,
when
An
is
is
done by mutation within the original vector, and no temporary storage vector
is
necessary.
We
first
numbers
1.
of n
list
We first
we
an item in the
select
list,
item
which we
in the
list,
call
The
rest of the
items in the
list
list.
A new
The order
list is
and the
left list,
in turn, followed
is,
The
quicksort algorithm
Step
on the items
is
lists.
Those
less
left
by the items
two
immaterial.
in the left
On
size,
and when
all
list is
empty
or
original
which
called
quicksort.
consists of a single
if it
list.
is
Otherwise,
it
It first
number. In these
numbers into
cases,
it
list
as its second
The
elements of the
first
third
its
fourth parameters.
list
list is
and
group,
and the second of the accumulators, rgroup, stores those elements that are
greater than or equal to the pivot to give us the right group.
collect
316
tests
list
The procedure
Is to determine whether
it is
less
than
Program 10.13
quicksort
(define quicksort
(letrec
((collect
(.caoc
Is) rgroup)))))))
(lambda (Is)
(if
Is
the pivot. If
it is, it
When
Is
finally
which
is
is
is
'0
conses
'())))))
it
is
conses
it
it
onto rgroup.
We
quicksort
It
it
sorts the
we
call
vector-
advantage
too
much
if
of
the
To
illustrate
in place (that
of the vector
#(649782569)
To
how
see
we place our
left
the item to the right of the pivot (the item with index 1) and our right index
finger
This
below the
is
last
illustrated
#(649782569)
10.2.3 Sorting
\
317
We now go
its final
position, so that all items to its left will be less than or equal to the pivot eind
items to
all
its
Searching Up.
1.
pivot and
We
if it is
left
move our
index finger
left
We
one entry to the right and compare that item with the pivot.
moving
pivot.
We
beyond the
left
2,
last item,
is
case,
continue
If
we pass
we have moved
to the
by:
#(649782569)
/
\
2.
We
Searching Down.
if it is
We
item,
not
left
less
left until
we stop
there. In
We
than the
we come to the
our example, we move down until we encounter
pivot.
is less
If
6.
#(649782569)
/
3.
Swapping. Swapping allows us to move both values from the wrong location
index finger,
left
index finger one item to the right and our right index
left.
This gives
us:
#(645782969)
/ \
We
repeat steps
and
2,
1,
is
2,
same
pivot, 6.
Since our
which
is less
index finger
is
pointing
moving
is
left.
This
gives:
#(645287969)
318
left
moving
right
We again
repeat steps 1,2, and 3 starting with our index fingers both pointing
to 8 with index 4
pointing to
index finger
to the
now
left
8,
is
which
is
pointing to
and comes
which
8,
to 2, which
is
it
stays where
it is.
is less
it
it
is
Our right
moves one
stays there.
We
have:
#(645287969)
4.
is
pointing.
is
When
left
index finger
is
is
#(245687969)
We next
left
to the left of the pivot 6 (these items are all less than 6); the pivot itself
up the middle
part;
and the
all
makes
#(245687969)
We now
apply Steps
through 4 to the
When we
left
and
We
vector-quicksort
in
Program
is
sorted.
is
done by the helping procedure qsort, which has as parameters the lowest
to be sorted.
As long
as there
is
more than one item in that part that is, the lowest index, low, is less than
the highest index, high the helping procedure partition (defined later) is
called to carry out Steps 1 though 4, and the final position of the pivot is
called middle. Then the qsort procedure is invoked on both the left part
and the right part.
and then
item
in the
group
invokes the local procedures search-up and search-down to carry out Steps
1 and 2 given above. The indices of the items that search-up and searchdown locate are named new-left and new-right, respectively. If new-left is
10.2.3 Sorting
319
Program 10.14
vector-quicksort
(lambda (v)
(letrec
((qsort (lambda (low high)
(if
low high)
(qsort
less
than new-right, the items with these indices are swapped, using the pro-
3.
is
new-right is returned
of partition is given in Program
The
definition
To
why
get an idea of
quicksort
0{n log2
is
n) for
some
lists, let's
assume
that the items to be sorted are well mixed so that the correct location of the
pivot
is
On
the
of the
each time a
list
contains n
left
1).
If
2"* items;
then
the
is
left
total
is
is
so after
passes,
passes, each
in all.
On
320
similar but
then the
into
is
when
more involved
them
there are
nm =
n logj n
if
the
list
0(n logjn).
the original
group contains
near
two groups
Thus
list is
ri
comparisons
is
group
list is
will contain
is
all.
is
m = logj n.
list,
items.
first
(actually n
list
n 1
items.
Thus
it
takes
n 1
left
group
is
comparisons
Program 10.15
paartition
(define partition
(letrec
((search
(laabda (left right)
(letrec
((search-up
(lambda (i)
(cond
((= i (addl right))
(subl i))
(search-down
(lambda (i)
(cond
((or (= i (subl left)) (< (vector-ref v i) pivot)) i)
(new-right (search-downright)))
(if
(<
new-left new-right)
(begin
(vector-swap! v new-left new-right)
new-right)))))))
(search (addl low) high)));)
Program 10.16
vector-swap!
(define vector-swap!
(lambda (vec
j)
(vector-set! vec
(vector-set! vec
temp))))
10.2.3 Sorting
321
it
empty
we
left
see
will take
(n
comparisons, which
is
it is
and
1)
(n
2)
-(n^
2)
Oin"^).
method
for sorting
like to
have
to do
alphabetical sorts. Strings can be compared to decide which precedes the other
in alphabetical order.
lexicographic order
is
through 9
all
first,
then
complete
is
discussed in
=^
also predicates
of
listing
given
There are
is
all
#t
expected things. The predicates string<? and string>? can be used in place
of < and > in the sorting programs to sort
names
the sort routine had been abstracted to take an additional argument rel, then
the alphabetical sort could have been accomplished by passing rel the value
string<? or string>?.
many
different
order.
for
is
referred to as a record.
name
first.
The
first
column
contains the
employee's identification number; the third column, the employee's age; the
322
Name
(define tablelO-17
'(("Smith, Harold W."
("Jones, Mary Ann"
("White, Thomas P."
("Williams, John"
("Brown, Susan E."
("August, Elizabeth"
("Jones, John Paul"
("Wilson, William W."
("Black, Burton P."
("Fox, Charles q."
("Blue, Benjamin J."
Table 10.17
2324
1888
3403
2451
3620
2221
1990
2455
3195
2400
3630
when
55
46
38
41
26
field
as a
To
sort these
is
called a field,
name
field
list
is
(or in
is
are
To
on the
or
data.
The
has a
we must
first
we
are going
We
first field,
making of the
field
list.
we
in
we
"Age."
some
and each
are sorting
49325)
65230)
27300)
41050)
18500)
44100)
63700)
41050)
31420)
52200)
18500)))
has the
it
list
Salary
supervisor;
Supervisor
1974
1965
1982
1970
1984
1971
1965
1970
1978
1981
1984
43
54
34
46
28
45
table represented as a
salary in dollars.
Yr.Emp
Age
Id
fields,
which case we
"Name."
is
One
can
We
same
must
(or rel
makes the comparison on the appropriate member of each
row and then moves the whole row as a unit as the sorting is done.
10.2.5
Which
it
of randomly generated
is
best?
numbers
10.2.5 Sorting
Many implementations
of
a positive
323
to
argument n and returns a pseudo-random number in the range
Program 10.18 defines random-list, which
n-1, including the end values.^
hcis as its output a list of n such randomly generated integers, each of which
integer
is
and n
between
Program
10.18
1.
random-list
(define random-list
(lambda (n)
(letrec ((build-list
(lambda (k)
(if
(zero? k)
'0
(cons (random n)
(build-list n))))
We
We can
measure the time that each of the three sorting procedures takes to
When we
it
its
which we now
argument arg,
it
tells
define.
us both
second.
We
way
calling a procedure
Such sequences
following way.
range
324
< x^ < n
1 is
In
Program 10.19
is
timer
(define timer
When
let
(var2 wa/2)
ivarn vain))
evaluated, there
is
no guarantee
not be allowed
Scheme
if
let
same
let
expression.
...
ivarn vain))
body)
which
is
let
Although the way of getting the time of day has not been standardized,
some way of either getting the time of day or of timing a procedure.
^
10.2.5 Sorting
eill
Schemes have
325
The
from
to right,
left
and
any ua/-part may contain var's from previous pair bindings. This enables us
timer
to define
in the following
way:
(define timer
(finish (time-of-day))
Sort
Number
in
Seconds
100
200
400
insertsort
0.55
2.69
10.76
nat-mergesort
0.17
0.38
0.88
quicksort
0.11
0.22
0.60
0.39
1.71
6.21
0.33
0.65
1.48
0.22
0.44
1.05
of Items
vector-insertsort
vector-mergesort
vector-quicksort
Table 10.20
The
Time
we have developed are given in Table 10.20."^ The three mutators vector-insertsort!,
vector-mergesort!, and vector-quicksort! were called by first making a
results of using
sort routines
copy of the vector to be sorted and then calling the timer on the invo-
local
vector-insertsort
we have
The time
for the
two
The
326
is
test
! !
We
list
of ran-
list
of integers from
to 100.
We
from
to 400.
shown
in
Number
to 200
and of
The
to vectors.
results are
Time
of Items
in
Seconds
101
201
401
insertsort
0.05
0.11
0.17
nat-mergesort
0.06
0.11
0.16
quicksort
0.38
1.37
5.98
vector-insertsort
0.05
0.11
0.17
vector-mergesort
0.28
0.66
1.42
vector-quicksort
0.44
1.59
5.93
Table 10.21
insertion sort
list,
is
much
is
slower.
We
we have
in
We
cannot recom-
mind
for
it.
There are
other sorting routines that have their advantages for specific kinds of
sorting jobs.
book.
lists
from
to 100, as
Table 10.21.
Sort
many
The
There
an extensive literature on
any further
this subject
this topic in
in this
Exercises
Exercise 10.1:
decr-ints
10.2.5 Sorting
its
argument, pro-
327
duces a
list
25, 50,
and
to
100,
1.
Use
this
procedure
why
these
lists
provide
all three.
nat-mergesort
Rewrite the definition of nat-mergesort so that it is curried and takes as its
first argument a binary relation rel and returns a procedure that takes a list
Exercise 10.2:
as
its
argument.
It
returns the
the
list
in
to sort a
list
example,
if
the
list
of
names
in lexicographic order
suitable
lists
of numerical
Exercise 10.3
fields,
and
in the case of
first
it
numerical
fields,
sorted alphabetically by
Name,
increasing order by Id, the third by decreasing order of Salary, and the fourth
We
mergesort
in
list is
grouped
merged pairwise
until there
is
Compare
and nat-mergesort to sort random lists of length 100, 200, and 400 numbers
and to do the insertions done in the second time tests. Write the definition of
a recursive vector version of mergesort that uses the two procedures vectormerge and vector-change given in this section. The algorithm is outlined
!
below.
a.
Make a
same length
as the vector
vec to be
sorted.
b.
first
and
its
328
and one
less
The
group
initial values
of
As long
c.
first
as
is less
than last,
let
may
g.
d.
e.
f.
Invoke vector-merge
is
Copy
g.
Compare
the times for this version of mergesort to sort the various test vectors
with the times for the iterative vector version and with the times for natural
lists.
10.3 Searching
Suppose we have a
containing
list
is
many
We
and
if it
Exercise 9.5.
frequently,
If
a method
the
more
and
efficient
number
and
list
is
is
list
game
in
is
thinking,
of questions.
is
The most
By
lies in
must
lie
asking
into
two
For
"Is
10.3 Searching
is
both
the questions
yes, the
is
is
number
first
in
100, including
is
is
accessed equally
answer
found,
of n items
example, the
is
a well-known guessing
this
it,
item
method
efficient
between
list is
guess the
list.
without finding
is
This more
not in the
is
list
to find an item,
If
list
list
lie
with each
329
question,
it
1,
number
is
determined.
repeated, so
it
is
found, where 2*
n; that
is,
fc
logj n.
is
Thus
a vector of 1,000 items that would take an average of 500 comparisons to find
an item using
linear search
would take
at
most 10 comparisons
to find the
item using binary search.* This points out the advantage of using a method
that
is
Since
we
shall
in vectors that
may
bineo-y search
program
in fact, in vectors of
names that
we
shall write
and returns a binary search procedure that takes a vector and a target as
parameters.
its
We
<, >,
kinds of searches mentioned above. Program 10.22 shows the code for such a
version of binary-search.
We apply this
as follows:
[1]
(let ((names (vector "Ann S" "Ben J" "Ed A" "Guy S" "Kay ")))
If
to
to
3S0
Program 10.22
binary- search
(define binary-seeurch
(lambda (rel)
((search
(leunbda (left right)
(if
(<
right left)
(search
this
(let ((names (vector "Ann S" "Ben J" "Ed A" "Guy S" "Kay W")))
Exercises
list-linear-search
Write a program list-linear-search that takes an arbitrary list of numbers
and a number and searches through the given list linearly from the beginning
Exercise 10.5:
until
it
finds the
number.
If it finds
list; if it
the number,
it
it
returns an
appropriate message.
Exercise 10.6
Write the procedures that are used to sort the personnel data
in
Table 10.17
on the field of names, and then use binary search to locate a given
name and
return the personnel data for that individual. Use vectors to store the data
sort routine
you wish.
331
We
is
a company,
is
an example of such a
who
company
table.
all
In accessing
we can ask
we can ask
for all people over 40 years of age whose salaries are over $50,000. We now
develop a relational calculus that will enable us to access data in this way
using the quantifiers f or-all and there-exists and the procedures setbuilder and set-map defined in Chapter 8. We assume in this section that
data
joined the
lists.
n arguments and Is
of proc. Then
is
((unlist operator)
list
of
that con-
takes
is
We
list
is
a procedure that
(list operandi
operandn))
equivalent to
{operator operandi
we
we
lists,
We
operandn)
5.
we do not want
each of which
is
use the set procedures to manipulate the information stored in the table.
For example,
if
we want
we convert
it
to a set using
332
Program
10.23
unlist
(define iinlist
(lambda (proc)
(lambda (Is)
(apply proc Is))))
of age.
names
We
in
general, find
if
is
over 25.
We
shall, in
it
them
directly.
(define age-test?
(unlist
Then we apply
test?
in the following
way:
all
=*
#t
Had we
(lambda
(neune
Then we apply
Fox
is
=^
#t
We now
say that
104
Relational Calculus
333
name, or there
supervisor's
of the
first
first
employee's supervisor."
precedes
s.
or there
supervisor's
s.
We
exists einother
name
is
is
If
the
employee's
first
denoted by
is
s.
in
name
is
denoted by n and
name
is
as follows:
((for-all
(unlist
(lambda (n
a y s p)
(or (8triiig<? n s)
((there-exists
(unlist
(string<? s* s)))))
8etlO-17)))))
setlO-17)
The parameters
ables different
first
lambda
lambda,
expression,
(and (string<? n n)
names
it
is
is
name
for if
to be chosen to be vari-
we had used n
we would have
cind s as
hcui
(8tring<? s s))
certednly not
what we
lambda expression
conflicts in
weuit.
Although the
as
false
is
August.)
set
of
cill
though
it
is
a set.
(define nametage
(unlist
(laimbda (name id age yr-emp superYisor salary)
SS4
We
To obtain the
If
we then
call
we get a table of all of the names in Table 10.17 followed by the field of ages.
The other fields have not been included. We call this new table the projection
of Table 10.17 onto the name and age fields. In a similar way, we can obtain
projections of Table 10.17 onto any of
its fields.
Sometimes we want to get the actual rows of the table for which some
predicate is true. In particular, suppose we want to get the data from the
table about
all
people
who
each one are the Id, the Age, the Year Employed, and the Salary.
We
for
write a
(define over-45?
(unlist
We
of setlO-17 consisting of
all
entries for
is
(define over45-set
To
get the desired output, namely, the Id, Age, Year Employed,
and Salary,
for each of the selected employees, we project the set over45-set onto the
four desired fields using set-map and then pass the resulting set to set->list
to construct the
new
table.
(set->list
(set -map
(unlist
over45-set))
=>
builds a
list
new
rows of
had we asked
335
Jones,
Jones,
Fox
M.A.
J.P.
Williams August
Blue
White
Figure 10.24
Wilson
Black
year employed, and the salary, we would have had two rows like (46 1970
fields over
in the set.
To
company
is
Blue
Jones.
under
J. P.
is
J. P.
The
is
organiza-
under imme-
Jones,
and M. A,
We
"Who
is
the
common supervisor
closest
these two,
We make
the
eissumption that each person has at most one immediate supervisor and that
the tree
is
is
The program will first start at one of the two members and build the path
up the chart until it goes as high as it can. The path will be a list consisting
of the names starting with one member, say. White, and containing (in order)
all of the names on the path until the top, M. A. Jones. To build this path, we
336
Program 10.25
find-supervisor
(define find-supervisor
(unlist
like
Smith
in the table,
determines his supervisor (Fox), and adds Smith to the path, then determines
Fox's supervisor, and so on.
person
When
added to the path, and the path terminates. The procedure that
is
definition
is
given in
is
Program
called
10.25.
When
if
that person's
supervisor; otherwise
The
strategy
say X and
y,
is
it
name
common
the rear of each path-list, where the two path-lists have the
is
to start at
same person
our case, M. A. Jones) and move simultaneously toward the front in both
until the corresponding elements in the
he
is
their closest
so that they
cdr's
down
now
the
common
we
is
lists
agree)
lists differ.
the closest
is
supervisor.
It is
comparing
first
split
two
elements.
(in
lists
common
apart at
easier to cdr
agree in their
lists
two
two
of a
returns false.
it
we use
name
10.17,
J. P.
down a
path-lists
supervisor.
list
Jones, so
from the
The procedure
y,
f ind-ccs then
Program 10.26.
When reading the code for closest-conunon-supervisor, keep in mind that
when closest-coinmon-supervisor is applied below, the parameter testprocedure is bound to find-supervisor. Since the tables we use are sets of
lists, we use the set operations pick and residue defined in Chapter 8 as the
closest-coinmon-supervisor
is
given in
When
is
337
Program 10.26
closest-common-supervisor
(lambda (test-procedure)
(lambda (table)
(letrec
((build-path
(lambda (tbl u)
(if (empty-set? tbl)
(list u)
(let ((next (pick tbl)))
(let ((v ((test-procedure next) u)))
(if (not v)
(x y)
(find-ccs
(reverse (build-path table x))
(reverse (build-path table y) ))))))))
[1]
(((closest-common-supervisor find-supervisor)
setlO-17)
"White, Thomas P." "Blue, Benjamin J.")
In this chapter,
vectors,
and
sets.
most convenient
We
lists,
chose the data structure for storing the data that was
we had
lists
in
We
lists
to be
types to store data. In later chapters, we shall introduce several more useful
data types, such as the one called objects with which we shall implement
stacks and queues (Chapter 12) and the one called streams (Chapter 15).
338
Exercises
Exercise 10.7:
There
is
set-builder-map
some redundancy in using both set-builder and set-map
to find the
projection of the set of those over 45 onto the fields Id, Age, Year Employed,
and
Salary.
We
(set-map proc
Instead
mines
if
true,
and
if
so
it
first
deter-
is
over-45?
(unlist
the-empty-set
setlO-17)
Exercise 10.8
Write a procedure that accesses the data in Table 10.17 and returns the names
and
identification
Exercise 10.9
Table 10.27 contains the monthly sales for January and February for the
employees
listed
in-
339
You may
ments (predicates,
find
it
to
some
of the procedures
given above.
'(
(2221
(2324
(2400
(2451
(2455
(3195
(3403
(3620
(3630
Table 10.27
Feb-Sales
33000)
49320)
52200)
31500)
25250)
Jan-Sales
22300
61080
41000
25550
31010
28800
72050
60500
31100
31100
26300
Id
(1888
(1990
16500)
50010)
40220)
22500)
22500)
19400)))
and February
Exercise 10.10
defined in
putes the paths using the local procedure build-path, which recursively pro-
is
later reversed
gument
so that
build-path
list iteratively.
The
also has
when
it is
accumulator
is
the order from the top of the tree to the bottom, and reversing
necessary
when
it is
Exercise 10.11:
used as an ar-
closest-common-supervisor
it is
list
in
no longer
List of Vectors
list
[1]
[2]
[3]
Redo
340
What
are its
Mutation
11
11.1
Overview
In Chapter 9,
vector.
The
in a different style.
With
side effects
on vectors, we showed
in
Chapter 10
11.2
what a
set!
implementation
set!
is
illustrated in
the following:
[1]
[2]
(f 5)
15
[3]
[4]
(f 5)
(* x 10)))
50
[5]
(writeln
(+ x 100))))
5))
(f
(* x 100)))
(f 5))
105
500
[6]
(f 5)
50
adds 10 to
expression
by
5
10.
now
We
its
is
is
The
returns 50.
let
when
Then a
the application of f to
its
let
set!
expression, (f 5)
expression
is
We may
let
is
is
is
used to
of (f 5)
argument
its
its
set!
is
Then
the value
again applied to
set!
5,
expression
think of the
set!
and
val.
is
recommend doing
set!.
so.
Such changes
it
in the
it
must have
been bound to some value either globally using define or locally using lambda
or one of the other binding forms.
We
in the following
implementation of stacks.
342
Mutatton
An
stack
is
This property
first
is
out." Thus,
first
pop, 30
is
is
10, 20,
we implement a stack
empty
list.
of the stack.
We
We
2, 3,
as a
list
The
of objects.
tests
list will
the
is
The procedure top returns the top of the stack, that is, the car
The procedure push adds its argument to the top of the stack.
!
is
4,
car of the
The
preceding it to show
Thus the stack containing the numbers 1,
and
removed,
purposes,
is
in,
in the
removed.
way of implementing
look at one
We now
is
last
argument. The
its
with
on top
will
be printed as
TOP:
12
With
3 4
[1]
(push!
'a)
[2]
(push!
'b)
[3]
(push!
'c)
[4]
(top)
c
[5]
(pop!)
[6]
(print-stack)
TOP: b a
We
Let us
suppose that we want to find the value of a procedure proc that on each
invocation requires a long computation before
it
returns an answer.
We
also
assume that we call this procedure often with various arguments. It would
save time if we could store each new value that the procedure computes in a
table,
is
is first
checked to see
Then
if
the already
34S
Program
11.1
(define empty?
(lambda
()
(null? stk)))
(define top
(lambda
()
(if (empty?)
(define print-stack
(lambda
()
(display "TOP:
")
"
")) stk)
(newline))
(define push!
(lambda (a)
(set! stk (cons a stk))))
(define pop!
(lambda
()
(if (empty?)
computed value
is
it is
it.
we
it
it.
is
If it
is
more
efficient to
have already been computed and searching through this table each time the
procedure
is
The data
is
structure that
already-computed values
a dotted pair (arg
344
Mutation
referred to as
is
we use
a
list,
computed
for
to serve as a table in
which we
is
call
is
Thus
if
the procedure
is
fib
for
We
arguments
would look
6,
lists
then table
is
((2
1)
more
efficient, since in
we
(cons 2 (cons
list
If
the
list
we
table
'())).
We
first
8)).
list.
of a
(6
3)
is
(4
like
and
2, 4,
first
use
is
is
cadr.
the
if
list
has four items, we include 4th for cadddr. These are easier to read than the
multiple car/cdr chains.
To
look up whether fib has already been computed for argument 4, the
procedure lookup
object obj, a
list
is
used.
four parameters, an
in
table or
tell
fail
how
If
no pair
and we invoke
there
to find
(lookup 4 '((1
pair.
is
and the
because they
f ailure-proc. These
known
its first
is
1)
when we
For example:
it.
(2 4 8)
(4 16 64)
(6 36 216))
(lambda
== 16
0))
and
(lookup 3 '((11
1)
(2 4 8)
(4 16 64)
(6 36 216))
()
=>
0))
In these examples,
table
is
list
is
The
tells
first
element
of three
found to be the
list
In the
first
example,
In the
345
second example, 3
is
first
is
returned.
The
nition
lookup
definition of
is
to search the
straightforward.
of pairs until
list
is
we
The
list.
not change in the recursion, we begin with a letrec expression to define a local
procedure, lookup, which has only the one parameter table. Because of lex-
Program
11.2
local procedure
of lookup.
lookup
(define lookup
(failure-proc)
(let ((pr (car table)))
(if (equal? (car pr) obj)
(success-proc pr)
(lookup (cdr table))))))))
(lookup table))))
We
lookup
as
its first
list
is
Scheme procedure
of pairs table.
If
a pair
is
(assoc 4 '((1) (2
1)
(assoc 5 '((1) (2 1)
The code
for assoc
is
5)
(4 3)
(6 8)))
(4 3)
(3 1 5)
(4 3)
(6 8)))
#f
(3
lookup.
We
We
are
proc as
346
Mutation
now ready
its
is
the
memoized
Program
assoc
11.3
(define assoc
Program
()
#f))))
memoize
11.4
(define memoize
(leimbda (proc)
(leunbda (pr)
(lambda
()
val)))))))
version of proc.
To memoize
The
definition of
memoize
is
we
first
define
fib as before:
(define fib
(lambda (n)
(if
n 2)
n
(+ (fib (- n
D)
(fib (- n 2))))))
We now
first
show two
different
Evaluate (fib-m 6)
computed
first.
recursively to get
f^cdr
its
value
8.
This value
is
is
in the
347
Program
memo -fib
11.5
(define memo-fib
(sHoize (lambda
:n)
(if
2)
n
(+
(memo--fib (- n
(memo--fib (-
set! line
is
n 2)))))))
and table
(f ib-m 6)
D)
is
now bound
new binding
is
to ((6
When
8)).
set
(fib-m 6)
If
pair (6
is
8) and by taking
we
its cdr,
first
time
(fib-m 100)
ever,
is
is
it
produces the
now
If this is
which
is
more than
is
10^^.
If,
calls
is
many
how-
contains only two items at this point. If the table does get large after
procedure
re-
in
tween the efficiency of the procedure evaluation and the table lookup. Later,
we
shall consider the use of vectors to represent the table of stored values.
Random
more
A
it
efficient
more
procedure fib
arguments
found,
its
itself.
5, 4, 3, 2,
(.arg
In
and
1.
va/)-pair
added
to table.
first
if
we
call
how we
write this
already
will save
(fib 7),
is
is
it is
the
table. This
memoized
is
is
called
known
time ui
sum
of
a great
version of
fib.
It is
the efficiency
348
Mutation
in
above:
[1]
[3]
Exercise
Exercise 11.1
To
see
(display
"
with arguments
6, 7,
and
if
expressions.
10.
reduces the
results.
Because the elements of a vector can be accessed randomly with equal ease,
vectors can be used effectively for
making
tables.
we
is
tests
is
is
When
used as the
list is
we can
is
list,
found.
the search
is
We
a largest value for the arguments that we store in the table, since
If
its
must fix
we must
349
To
first
determine whether that value has already been entered into the table.
We
proc
for a given
arg)
The
let
test to
'
Program
11.6
vector-memoize
(define vector-meBoize
(lajBbda (max-arg)
(lambda (proc)
(let ((table (Make-vector (addl max-arg)
(lambda
'())))
(eurg)
(proc arg)
(let ((item-stored (vector-ref table arg)))
(if (pair? item-stored)
(car item-stored)
(let ((val (proc arg)))
(vector-set
table
curg
(list val))
val)))))))))
This memoizing procedure can be used in exactly the same way as the one
we
many
vector
We
This
We
350
entries
It is
more
efficient
when
have been made into the table since the random access of the
makes lookup
faster.
is
shall look at a
Mutation
way of removing
this restriction
lists
when we
(define memo-fib
(
(vector-memoize 100)
(lambda (n)
(if
n 2)
n
(+ (memo-fib (- n 1))
(memo-fib (- n 2)))))))
ample.
(set
First,
set!
vc.r
expression
is
is
val.
Then Scheme
it
We
an error message,
in
for
It is
is
bound
many implemen-
set
changes only
important to realize
clause
extended ex-
different things,
is
existing bindings;
!
in this
val)
that set
effect,
rely
its
and
in
rebinding as a side
effect
your
in
means that
last
ments executed
ment that
is
given by (set!
a 10).
output statement that prints the value of the variable a on the screen
is
is
given
is
An
If
is,
imperative
style.
Recall
first
an
effect of
iterative version of
member?:
351
(define member?
An
Program
11.7
is
Program
given in
11.7.
(define member?
(label))))
(letrec
(
(start
(lambda
()
(cond
((null? Is) f)
(reduce
(lambda
(set
()
Is (cdr Is))
(goto start))))
(goto start)))))
is its
argument. The
is
letrec
expression defines the thunks, which control the order in which the statements
are executed in the program. In the last line of the program,
first
thunk invoked
is
steirt.
Is
start
is
empty.
tests
In the
If so,
whether the
#f
is
first
The body
first
of this thunk
is
we
a cond expression
returned.
value in the
list
Is
is
in the
thunk
is returned. The else clause in the thunk start moves control to the
body of reduce, where the list Is is assigned the value (cdr Is) and control
is moved back to start. It is important to realize that no variable is passed
to start when control is moved to start. Instead, the value assigned to the
value #t
352
Mutation
Program
while-proc
11.8
(define while-proc
()
(pred-th)
(begin
(body-th)
(loop))))))
(loop))))
variable Is
is
is
new
An
sibility of
the pos-
is
structions. This
is
done
in
a language
like
Scheme by
One method
We
can
in-
repetitively invoking a
reached.
is
programming
We
definition
Here,
we
In the
loop, the predicate thunk pred-th tests whether the list Is is empty or the
variable ans is true. As long as neither one is true, the body thunk body-th is
first
value in the
list
Is
is
item.
If it is,
then
353
ams
is
Otherwise, the
list
Is
is
(cdr Is). The loop then repeats the invocation of the predicate thunk, and
true, the
(define member?
((ans #f))
(while-proc
(lambda
(not
(lambda
(if
ans #t)
ans)))
Program
duce a
replacing recursion with the explicit construction of the return table, which
we implement
as a stack.
(define swapper
(lambda (a b Is)
(letrec ((loop (lambda (Is*)
(cond
((null? Is*)
'())
(loop Is))))
Most languages have a looping mechanism that repeats some operation until
a terminating condition is satisfied. We once again use the procedure nhileproc for that purpose. Notice that in the recursive program for swapper,
until Is* is empty, something is consed onto the recursive invocation of loop
354
Mutation
on each loop.
We accomplish this
is
added
to a return table
program by pushing
empty, we repeatedly
in our imperative-style
when Is*
is
finally
cons the top of the stack onto our answer and pop the stack until the stack
is
will
first
it is
is
Program
globally defined
and
swapper
11.9
(define swapper
(leunbda (a b Is)
(ans '()))
(while-proc
(lambda
()
(lambda
()
(cond
(car Is*))))
(print-stack)
(set! Is* (cdr Is*))))
(while-proc
(lambda
()
(not (empty?)))
(lambda
(set! ans (cons (top) ans))
;
(writeln "Answer =
(pop
"
ans)
(print -stack)
))
ans)))
in front of these
An example
output expressions
To
of an application of swapper
is
given in
355
[1]
12 '(123123))
(swapper
TOP: 2
TOP:
12
TOP: 3
TOP: 2 3
12
12
TOP:
TOP: 3
2 3
Answer = (3)
TOP:
12
12
Answer = (13)
TOP: 2 3
Answer
=(2 13)
TOP: 3
Answer
=(3213)
TOP:
12
Answer
=(13213)
TOP: 2
Answer
=(213213)
TOP:
(213213)
Figure 11.10
first
loop,
is
being
loop.
we had
needed two stacks, say stkl and stk2, we would have had to define two
sets
of stack operations and use the right ones with each of the two stacks. This
is
this
using what
The
is
stack
known
is
as object-oriented
programming.
is
Its state
object
We
An
we can consider
The mutators such as set and vector-set and the procedures derived from
them such as push! and pop! are used to change the state of objects. In most
of our Scheme programs, we can use procedure applications and recursion and
avoid the use of mutators altogether. There will be times, however, when we
!
find
356
it
Mutation
In
mathematics and
logic,
a function
is
in
Scheme.
returns the
is
is
completely determined by
its
developed this
programs
to describe the
It
in Section 8.5
it is
effects
arguments; that
its
is,
the function
is
more accurate
to use
the term procedure instead oi function since side effects are allowed, and this
is
Exercises
Exercise 11.2:
pascal-trieingle
above
it
and on each
side of
in the line
are
shown
below:
1
1
13
14
1
10
10
in the
nth
k).
We
kth.
is
Analyze
this
we
is
computed.
(pascal-triangle
(pascal-triangle
(pascal-triangle
(pascal-triangle
=>
252
12 6)
924
3432
14 7)
16 8) ==> 12870
10 5)
^
^
357
Exercise 11.3:
timer2
Write the definition of a procedure timer 2 that finds the time elapsed from
the time a procedure proc
is
returned,
is
exercise,
10 5),
triangle 16
8).
Exercise 11. 4:
It
ferent
number
n,
combinations
is
list
The notation
n!
number
(^)
of n distinct objects.
dif-
This
is
It
f.,(^_f^\,
Compare
it
it
for the
compute (combinations
100 50).
Exercise 11.5:
lookup2
five
arguments: two
Scheme objects objl and obj2, and a list of triples trilist and a success
and a failure continuation. It searches through the list from beginning to end
looking for a triple in which the first element is ob j 1 and the second element is
obj2.
If
such a triple
is
found,
it
is
'((a b 5) (a c 7) (b c 9))
(lambda (tr) tr) (lambda ()'()))
(lookup2 'a 'c '((a b 5) (c a 7) (b c 9))
(lambda (tr) tr) (lambda ()'()))
(looJnip2 'a 'c
Exercise 11.6:
=*
(a c 7)
=>
()
memoize2
Memoize
the procedure
pascal-triangle
358
Mutation
Program
11.11
Mystery program
(define nystery
(lambda (a b Is)
(let ((Is* Is) (ans '()) (goto (lambda (label) (label))))
(letrec
(
(push
(Isuabda
(cond
(czu:
(reduce
(Isunbda
(goto push)))
(pop
(lambda
()
(cond
((empty?)
eins)
(else
(set! ans (cons (top) ans))
(pop
(goto pop))))))
(goto push)))))
timer*
arguments.
For example,
if
proc
is
number of
call
(timer* proc
Exercise 11.9
In the imperative-style
359
Exercise 11.10
program
In the imperative-style
certain steps
for
is
true.
In
are not implemented so another device must be used. Such languages often
As
in the first
means
Program
11.11
is
is
written in imperative
and invokes various thunks to move the control to the body of the thunks.
that a global stack stk is initially empty. What is returned when we
Assume
invoke:
(mystery 'a
The box-and-pointer
'(crazy))
'z
Cons
Cells
An
object that
is
way
of
not a pair,
is
(i.e.,
cell,
which
is
a double box (a
horizontal rectangle divided into two boxes by a vertical line) with a pointer
box on the
by the cons
cell.
points to the
ceir,
4)
is
The
list
(3
is 4.
which
When
returned.
is 3,
(cons 3 4)
We
call the
is
The value
left
side
left
is
list
car pointer and the pointer from the right side of a cons
for
pointer
the improper
cdr, which
left
cell.
The
cell
cells,
one
for
number 3, and
the cdr pointer of the first cons cell points to the second cons cell. The car
pointer of the second cons cell points to the number 4, and the cdr pointer
of the second cons cell points to the number 5. In this way, we can build up
this value.
360
Mutation
The
first
cons
cell
points to the
-j
>[A'
>^
yt
(cons
(cons
3 4)
(cons 4 5))
(a)
Figure 11.12
(b)
Box-and-pointer diagrams
3L
>r
(cons
yr
l4
3 '())
5 '())))
(b)
(a)
Figure 11.13
lists
expressions.
We now
list
(cons 3
'
how
shall
we
the cons
The
cell.
list
(3).
We
the
This
empty
is
list
by drawing a diagonal
We
indicate
as (3 4 5),
interesting
Scheme displays
list.
is
list
Another
is
361
The
first
cons
creates a cell in which the car pointer points to the cons cell created by the
second cons, in which the car pointer points to 3 and the cdr pointer indicates
( )
The
The
cons
first
cell
cell
cell
created by
and
its
cdr
5,
(cons (cons
Figure 11.14
If
we
3 '())
(cons 4 (cons
5 '())))
Box-and-pointer diagram
define a to be (cons 3
'
()) by writing
we can
If
cell
to
we can think
'())))
representing (cons 3
it
S62
Mutation
>
(set! a
(cons 4 (cons 5
'())))
(b)
Figure 11.15
Now
(define a (cons
set!
as:
(cons 2 '())))
We
The cons
same
a cons
as does a
cell
to the
same
This
is
cell
cell (to
which c points)
in
clear
from
c,
and a
=>
(1 2), b
=*
actually do change the objects to which they are applied. For example,
we
which
when
illustrated in Fig-
(set-car! b a)
363
/"
(a)
/"
(b)
(c)
Figure 11.16
(define
made
same
to point to the
cell
to which b points
a.
is
disconnected and
This
is
illustrated in
=
=*
(Cl 2) 4 5)
(1
2)
so that
list
which
is
now "garbage"
diagrams
Mutation
points to ua/ite.
and d defined by
364
it
(define c (cons
In
(cons 6 '()))))
The box-and-pointer
>
^
|r
5K
Figure 11.17
Let us
first
(set-car! b a)
in Figure 11.16
define h to be
so that w
We
=>
pause to
make an important
we
From
#t
we next
Two
see that
(eq? (car w) c)
If
if
same chain of
linked
cells.
call
(set-cdr! c d)
is
changed to
refer to
using procedures
like
set-cair
Thus
care
all
=* (14
in the list
365
{/
3
H /
-^
>
>r
w
Figure 11.18
=>
(eq? (car w) c)
->
ji
7^
1
#t
/!i
J
,/
1
1
w
Figure 11.19
occur.
[4
>
(set-cdr! c d)
in Figure 11.18
the
list
structure of data objects, but the values that they return are unspecified and
may
differ in different
S66
Mutation
it is
necessary
Figure 11.20
>
(define x (append
c d))
defined in
Program
4.1 as:
(define append
(null? Isl)
ls2
(cons
If c
(cau:
in
and
(define x (append c d))
then append makes a copy of c and changes the cdr pointer of the
cell in this
copy to point to
d. (See
last
cons
367
Program
11.21
last-pair
(lambda (x)
(if
x)))
Program 11.22
append!
(define append!
(begin
(set-cdr! (last-pair Isl) ls2)
Isl)
ls2)))
(1 2 3 4 5 6)
>
In
(1 2 3)
(4 5 6)
((3
2 3)
(4 5 6))
another. However,
it
it
list
to
should not
the
Program
list
11.21),
which takes as
argument a nonempty
(last-pair '(1
2 3))
list.
list
and returns
For example:
(3)
We
list
Isl until
it
list
Mutation
down
the
368
its
>
\N
.^
>
>
y-
i
A
U
~y
>
/"
/
X
11
k
W
Figure 11.23
then y
is
d. (See
y
c
in
We now
Icist
cons
to
(1 2 3 4 5 6)
(4 5 6)
(1 2 3 4 5 6)
=*
((1
:>
3 4 5 6)
(4 5 6))
append! on
c, for
the
it
originally
makes a copy of
c,
Thus each
set-cdr or
c.
,
which also
not changed
is
append
cell in c
have
(1 2 3 4 5 6)
=>
=^
The
<
Figure 11.23.)
lists
effects.
We
must be
369
^^
-^
^2
'
j_
u
Figure 11.24
j]
set-
cdr!, and append!. In the next chapter, we shall see examples where these
procedures can safely be used because the variables affected are local and the
side effects can be controlled.
Exercises
Exercise 11.11
2 3)))
z)))
Exercise 11.12
Write a
let
structure
shown
in the box-and-pointer
diagram
in Figure 11.24.
Exercise 11.13
a.
11)))
(set-caur! x x)
(set-cdr! x x)
x)
370
Mutation
b.
c.
list
as
its
cells.
all
occur-
cells.
Exercise 11.1
results:
(define mystery
(lambdaCx)
(let ((box (last-pair x)))
(set-cdr! box x)
x)))
[2] (define ans (mystery (list 'a 'b 'c 'd)))
[3] ans
[1]
Exercise 11.15
Let us consider only
cell
of the
list
list.
For
example,
(let ((i (list 'a 'b 'c 'd 'e)))
(set-cdr! (last-pair x)
x)
We can
list will
lists, it
(writeln x) ==^
(abcdecde
...)
(abcdecde
reconstruct a
list like
the last of
nine elements.
its
Exercise 11.16:
if
list is
flat cycle.
string "
Also,
..." as
efface
and
if it
efface
in
x, y, z, a, a*, b, b*, c,
and c* before
test-efface.
371
(define efface
(lambda (x Is)
(cond
((null? Is)
'())
(set-cdr! Is z)
Is)))))
(define test-efface
(lambda
(let ((x (cons 1 '())))
(let ((y (cons 2 x)))
(let ((z (cons 3 y)))
(let ((a (cons 4 z)) (a* (cons 40 z)))
(let ((b (cons 5 a)) (b* (cons 50 a)))
(let ((c (cons 6 b)) (c* (cons 60 b)))
(writeln x y z a a* b b* c c*)
(efface 3 c)
(writeln x y z a a* b b* c c*)))))))))
Exercise 11.17
Using the definition of efface from Exercise 11.16, describe the behavior of
difference.
(define test-efface2
(lambda
(let ((Is (list 5 4 3 2 1)))
(define test-efface3
(lambda
(let ((Is (list 5 4 3 2 1)))
(writeln (efface 5 Is))
Is)))
Exercise 11.18:
smudge
and
372
Mutation
smudge
in
x, y, z, a, a*, b, b*, c,
test-smudge.
and c* before
(define smudge
(Icunbda (x Is)
(letrec
((smudge/x
(lambda (Is*)
(cond
Is
(begin
(smudge/x Is)
Is)))))
(define shift-down
(lambda (boxl box2)
(set-car! boxl (car box2))
(set-cdr! boxl (cdr box2))))
(define test-smudge
(lambda
()
'())))
(writeln x y z a a* b b* c c*)
(smudge 3c)
(writeln x y z a a* b b*
Exercise 11.19:
It is
c*)))))))))
count-pairs
the
number of cons
cells in
a data struc-
seen-pairs* and
the helping
predicate dont-count?.
SIS
(begin
(set!
(lambda (s)
(or (not (pair? s))
a.
(member? s *seen-pairs*))))
(define test-count-pairs
(lambda
()
(set-cdr! (last-pair x) x)
b.
Why
Rewrite count -pairs functionally so that the two answers are the
ent?
gram
c.
in Pro-
Rewrite count -pairs using local state, which gets changed with set
Here
is
a skeleton:
(lambda (pr)
(covmt -pairs/seen pr '())))
374
10.5.
Mutation
...)))
d.
Rewrite count-pairs using private local state. Hint: Look at the skele-
We
ton below.
must
set
is
list
just prior to
a skeleton:
(letrec
((count (lambda (pr)
...)))
(lambda (pr)
(set! seen-pairs '())
(count pr)))))
e.
empty list after invoking count instead of before invoking count. This
way we know that seen-pairs is always the empty list before and after
invoking count -pairs.
are related.
Work them
in order
and you
will learn
Turing Tapes
Exercise 11.20:
list
an unbounded
list
O's as left
and
cbaxy...). We call
Consider a
such a
tape, or just
We
tape.
use a positive
number
of
OcbaxyO...).
as the
border symbol; no border value can appear within the interesting information
on the tape,
for if
it
did then
it
is
Tapes can be
is
the
c,
one
is
at,
first
is
which
over-
is
replaced by
c.
We
can characterize
the relation between overwrite and at with the following equation. Let t be
a tape and
let c
be a character; then:
(at (overwrite c t))
The
and fourth procedures are left and right. These take a tape
and return an equivalent tape except that the character being read is the one
third
375
is
unbounded
We
have the
in
now a
no concern about
falling off
identities:
is
is
tape
We
refer to this
either
left or
which to move:
(define reconfigure
We now
a tape
and
is
right part.
The
(a b c 0).
the tape
is
left
The
left
finite lists.
We call
these two
it is
left
we are
of where
part
represented by the
lists left
((a b c 0) (x y 0)).
(x y 0). Thus,
is
We
at and overwrite:
(define at
(lanbda (tape)
(let ((right-part (2nd tape)))
(.car
right-paurt))))
(define overwrite
We
Let us consider
what is involved in moving to the right. In our example this would mean that
we are looking at y. If that is so, then the right part would become (y 0).
What would happen to the x? Since it is now to the left of where we are
376
Mutation
reading,
it
is
first
left
become the
first
item
try at right:
(define right
(lambda (tape)
(let (deft-part (1st tape)) (right -part (2nd tape)))
(let ((new-left-part (cons (car right -part) left-part))
This
is
it
is
replace
it
((OyxabcO)
we must
))
tape ((y x a b c 0)
()),
If
and that
new
new-right-part
is
the
empty
list,
(define right
(lambda (tape)
(let (deft-part (1st tape)) (right -part (2nd tape)))
(let ((new-left-part (cons (ceir right -part) left-peirt))
(define check-null
(Icimbda (part)
(if
(null? part)
(list 0)
part)))
test
(define test-reconfigure
(Isunbda
(let ((tapel (list (list 'a 'b 'c 0) (list 'x 'y 0))))
(let ((tape2 (reconfigure tapel 'u 'right))
(tapeS (reconfigure tapel 'd 'left)))
(let ((tape4 (reconfigure tape2 'v 'right))
'e
'left)))
'f
'left)))
377
Exercise 11.21:
list->tape, tape->list
first
list,
The
no
same as (right
t) minus trailing zeros. For example, if Is is (x y), then (list->tape Is)
returns ((0) (x y 0)). The procedure tape->list takes a tape and returns
a list. The resultant list does not keep track of where on the tape it is reading.
Hence, it is not always the case that (list->tape (tape->list t)) = t;
however, it is always the case that (tape->list (list->tape Is)) = Is.
For example, if the tape, t, is ((a b c 0) (x y 0)), then (tape->list t)
(c b a x y)) is ((0) (c b a x y 0)),
is (c b a X y), but (list->tape
not ((a b c 0) (x y 0)). Not only must the left part be reversed, but no
O's should appear in the resultant list. Rewrite test-reconfigure so that it
uses list->tape and tape->list.
O's
t,
is
the
'
Exercise 11.22
In the procedure test-reconf iguxe from the previous exercise,
tapel
twice.
used as an argument
in
More
we used
frequently, a tape
is
ment:
[1]
(define shifter
(letrec
((shift-to-0
(lambda (tape)
(let ((c (at tape)))
(cond
((equal? c 0) tape)
(else (shift-to-0 (reconfigure tape
'right))))))))
shift-to-0))
[2]
When
the tape
is
each time we reconfigure the tape. For example, we can redefine overwrite
to change the value that at returns just by using set-car!:
(define overwrite
tape)))
378
Mutation
we exchanged one invocation of setcar! for three uses of cons and one use of cdr, but test-reconfigure no
longer produces the same result. Why? Redefine right and left to use as
few invocations of cons as possible. Test shifter as in [2].
In changing the definition of overwrite,
Exercise 11.23
We
(list->tape '())).
(i.e,
(loopright
(lambda (tape)
(let ((c (at tape)))
(cond
((equal?
'a)
(maybe-done
(lambda (tape)
(let ((c (at tape)))
(cond
((equal?
'a)
(continue
(lambda (tape)
(let ((c (at tape)))
(cond
((equal?
'a)
loopright)
(define endless-growth
(letrec
((loop
(leunbda (tape)
(cond
((equal?
0)
loop))
379
(define perpetual-motion
(letrec
((this-way
(lambda (tape)
(let ((c (at tape)))
(cond
((equal? c 'a)
'right)))
(that-way
(lambda (tape)
(let ((c (at tape)))
(cond
((equal?
'a)
'left)))
this-way))
(define pendulum
(letrec
( (loopright
(Icifflbda (tape)
(let ((c (at tape)))
(cond
((equal? c 'a)
(loopright (reconf igrire tape 'a 'right)))
(else (loopleft (reconfigure tape 'a 'left)))))))
(loopleft
(lambda (tape)
(let ((c (at tape)))
(cond
((equal? c 'a)
(loopleft (reconfigure tape 'a 'left)))
(else (loopright (reconfigure tape 'a 'right))))))))
loopright))
Exercise 11.24
Then
it
the current character and either returns the reconfigured tape or passes
be represented by:
this line as follows:
380
Mutation
We
first
cond
line of
continue
in
the state of
continue,
of five
busy-beaver could
From
list
it
if there is
We
an
can interpret
a,
overwrite
it
move left, and consider only the lines that start with raaybe-done.
The entire busy-beaver procedure could be represented by a list of all the
with an a,
(define busy-beaver-lines
'((loopright a a right loopright)
a right maybe-done)
(loopright
(maybe-done
(continue
We
beaver-lines)).
We
also
we
computation
start the
is
at
self-explanatory.
will get
lines, like
result as
far, define
the busy-beaver-lines,
by run-lines.
(define run-lines
((driver
(lambda (state tape)
(if (eq? state
'halt)
tape
(let ((matching-line
(next-state matching-line)
(reconfigure
tape
(next-char matching-line)
Such a
set of lines
is
named
for
Alan M. Turing.
he could
Then he showed
that no one can write a procedure test-lines, like run-lines, that takes
381
an arbitrary machine and an arbitrary tape and determines whether (runlines machine tape) halts. This result is so important that it has been
given a name, the halting problem. All this was done in 1936!
Exercise 11.25
Often
it is
possible to
configure, there
is
remove a
test
a superfluous
test.
Exercise 11.26:
New
Representation
list
it
is
reading separately.
of three elements
Then we could
redefine
cis
follows:
(define overwrite
(define right
(lambda (tape)
(let ((char (1st tape))
Use
and
test
busy-beaver.
382
Mutation
is
minimal.
Then
redefine all
Object-Oriented Programming
12
12.1
Overview
different perspective
on computing
is
ming. In this style of programming, certain objects are defined that respond
to messages passed to them.
Figuratively,
as a
The input
is
the message passed to the object, the object does the computation, and the
output
is
we
lustrated.
We
and
see
how such
data
and queues.
In Chapters 3
we
5,
and Gauges
il-
of the representation of the data and are based on certain predefined basic
procedures, including the constructors and selectors used on the data type.
The
actual representation of the data was then used only in defining these
basic procedures.
We
It is
not necessary
to use them.
object
is
pop
This
offers
it
it
possible to change the internal representation of the object without the user's
being aware of any changes. Before looking at stacks and queues, we introduce
the
we
Ccise
expression, which
makes
it
shall study.
12.2.1
Scheme provides a
special
selects
one of a
se-
quence of clauses to evaluate based upon the value of an argument (or message) that
that
tells
it is
passed.
us whether a letter
is
is
used, let us
look at a procedure
first
a vowel or a consonant.
We
can define
it
as
(define vowel-or-consoneint
(lambda (letter)
(cond
((or (eq? letter 'a)
(eq? letter 'e)
'vowel)
(else 'consonant))))
This procedure can also be defined using the special form case as follows:
(define vowel-or-consonant
(leUDbda (letter)
(case letter
((a e i
'vowel)
u)
(else 'consonant))))
The
the
value of letter
first
is
following the
expression.
list
Thus
of keys
if
is
there
is
is
list
is
e,
i,
o,
or u,
vowel
returned. In case
more convenient
a,
letter evaluates
384
of case
is
Object-Oriented Programming
it is
is
to one of the
with the possible key values rather than the cond expression, which must
The syntax
in
five vowels, it is
If
(keys) in the
it
list
(case target
(.keys expri expT2
)
.))
where target
is
an expression that
is
evaluated and
which
is
its
is
value
list
is
compared
of items each of
matched (using eqv?) with the value of target to decide which of the
When the first such match is found, the
expressions expr
of the last
match
is
is
returned (there
is
expr
...
some
unspecified value
returned.
if
It is
If
no
If
no
good programming
style
then
always to
Below are some additional simple examples demonstrating the use of case:
[1]
(case 'b
((a)
((b)
((c)
'c
'()))
((2468)
((13579)
(else "zero"))
we
we
representations of the data, which are not supposed to be apparent to the user.
In order to secure the data structures used,
we introduce,
its
in
Program
12.1,
and Gauges
385
Program
for-eflect-only
12.1
"unspecified value"))
Boxes
12.2.2
box
is
five
value
initial
is
it is
needed
We
The operation
A new
later.
in the
box
is
use one of
update!
called show.
Another
is
kind of object
is
is
what
"box".
In
update
show, swap
reset
and type.
The
To apply one
of
(object
where object
is
'
in fact,
(send object
The
386
'
m,ethod-name operand
Object-Oriented Programming
...)
box-a that
is
initialized
mechanism
is
for constructing
initialized
with
5.
We
shall describe
[I]
[2]
[3]
[4]
5
[5]
[6]
3
[7]
[8]
[9]
3
[10]
[II]
[12]
"box"
[13]
to box-a,
In
in order to see
and
Program
in [5]
12.2,
what
is
in order to
we
define
stored in box-a,
box-maker.
It
takes as
its
argument an
initial
num-
It
parameter
list is
object that
we
is
refer to as
the mes-
387
Program
12.2
box-maker
(define box-maker
(leunbda (init- value)
(lambda msg
(case (1st msg)
((type) "box")
((show) contents)
ans)
Program
12.3
delegate
(define delegate
respectively.
Program
We
also use
msg
delegate
defined in
12.3.
box to
its initial
value,
init-value,
swap
,
!
It is initialized
let
respond to
is
reached, no
is
it is
introduced
with init-value.
new value
the
for
Whenever
the method name, so the
but the old value ans that was stored in the box
message
is
is
returned.
(We
find that
it is
more suggestive
name
^ When an object cannot respond to a message, there are mechanisms other than delegation
which have been developed. One common mechanism is inheritance. We have chosen to
use delegation instead of inheritance; however, aJl programs expressible with inheritauice
388
Object-Oriented Programming
Program
12.4
base-object
(define base-object
(lambda msg
(case (1st msg)
((type) "base-object")
(else invalid-method-name-indicator) )
Program
12.5
send
(define send
(lambda args
(let ((object
"sent to object of
(object 'type)
"type.")
try)))))
same by our
is
simplification
delegated
is
the
is
base-
bound
to
definitions of base-object
We
shall define
many
These
for
which there
that
same
Programs
12.4
and
The
12.5.
diff'erent
is
in
all
will
call structure
and send takes the appropriate action. When writing the definitions of the
object makers and when using the objects, we must remember that:
and Gauges
389
1.
2.
the message to
3.
object,
which
some
in
else clause
cases
may
should delegate
be base-object.
the box
The
just a variable.
is
We
such as a cons
user
is
cell,
maker, init-value
is
In the
program below
a cons
for
cell,
box-
which
we denote by cell.
stored in
Program
box-maker (Alternative)
12.6
(define box-maker
(lambda (init-value)
(let ((cell (cons init-value "any value")))
(lambda msg
(case (1st msg)
((type) "box")
((show) (car cell))
(cju:
cell)))
12.2.3 Counters
counter
is
arguments: the
initial
when
update
390
it
,
!
is
a counter with
updated.
rule.
it is
called,
10 subl)
initial
is
initial
Object-Oriented Programming
Program
12.7
(define counter-maker
The counter
When
initial
value
initial
value
updated, we write:
(coimter-meJcer
The counter
is
(+ 5 x)))
(launbda (x)
the
Thus
if
them
to the
box
is
called delegation.
The work
of the counter
is
"delegated"
The approach
of catching the
catch
is
all
only one
the
and Gauges
391
Program
12.8
(define counter-maker
same
we
effect,
which enables
12.2.4
An
many
illegal ones,
it
legal
illegal
method names.
method names,
is
it.
If
legal
version of counter-maker,
Accumulators
accumulator
receives a
is
initial
v,
For example,
if
ace
is
an accumulator that
its
it is
100 and
defined by
and
(send ace 'update! 10)
causes the
number 90
to be stored in ace. If
write
392
is
Object-Oriented Programming
25,
we
Program
12.9
accumulator-maiker
(define accumulator-meiker
(IcUDbda (init-value binary-proc)
((type) "accumulator")
((update!
The accumulator
its
and a
to the
values. In addition to
value,
it
uses delegation
12.2.5
gauge
Gauges
is
a counter, but
it
The one
called
is
to count
up
is
gauge
is
similar to
up
is
called
When
It
to
two
box
called total.
unary-proc-
invoked on the value stored in total to get the new value stored in total.
Similarly, when the gauge receives the message down!, the update procedure
unary-proc-down is invoked on the value stored in total to get the new value
stored in total. The gauge also responds to the messages show and reset
by delegation from total. For example, to create a gauge g with initial value
10, which either adds 1 or subtracts 1, we write
and
(send g 'up!)
causes the
number 11
to be stored in g, while
393
Program 12.10
gauge-maker
(define gauge-mciker
(lambda msg
(case (1st msg)
((type) "gauge")
((up!) (send total 'update!
(send g 'down!)
returns the
number
stored in g to 10.
definition
of gauge-maker.
Exercises
Exercise 12.1:
acc-max
updated,
imum
it
it is
compares the value stored with a new value and stores the majc-
of the two.
numbers
Then
3, 7, 2, 4,
test acc-meix
10, 1, 5
and
by updating
find the
it
in succession
with the
shov message.
Exercise 12.2:
double-box-meJter
item2, and stores these values in two boxes, the left and right, respectively.
An
Exercise 12.3:
394
update-right
and reset
accumulator-maJcer, gauge-meiker
In the definitions of
Object-Oriented Programming
disable
all
illegal
legal
others.
No
it
satisfies
the predicate.
For example,
If
if
value
a value
is
stored in a
fails to satisfy
the predicate
(lambda
is
(and (> n 0) (< n 100))) and we try to bring the restricted counter
up to
105,
it
Exercise 12.5
Define the hour hand of a 12-hour clock as a restricted counter.
(See the
preceding exercise.)
Exercise 12.6
Define a 12-hour clock that has both a minute and an hour hand. This clock
is
to be constructed
clock,
will
its
One
of
them
will
be the 12-hour
Such a counter
is
created
is
of the clock
is
is
invoked in place of
When
is
used not
The new
clock
is itself
Do
not
to be an object created by
exercise.)
Exercise 12.7
Exercise 12.8
Is it possible to
a box-maker?
possible to
12.3 Stacks
395
12.3 Stacks
is
the rack of trays in a cafeteria, in which one takes the top one,
and trays are added from the top. As the stack builds up, the item that weis
put on first is buried deeper and deeper, and as things are removed from the
stack, the one that was put on first is the last one to be removed. The item
that was added to the stack last is the first one to be removed. Thus a stack
is referred to as a last-in-first- out data structure, or a LIFO.
The
it;
empty?, which
push
pop
An
,
!
,
!
tests
empty.
is
s,
and
is
The
The two
In the definitions of r
and
s,
a procedure of no arguments.
is,
[2].
stacks, r
we
and
see that
Its definition
the representation,
we can
alter
names are passed as messages to the stack, the results seen by the user
same as those produced by the above code. Even when the stack is
printed, it does not show the internal representation of the stack.
their
are the
Exercise
Exercise 12.9
2).
In
396
brackets
'[',']',
and braces
Object-Oriented Programming
'{','}'.
Here
is
all
'(',
three
(define r (stack-aaker)
(define s (stack-maker))
(send s 'print)
[I]
[2]
[3]
TOP:
(send r 'print)
[4]
TOP:
[5]
(send
'eapty?)
(send
(send
(send
(send
'push!
'a)
'push!
'b)
'push!
'c)
'top)
tt
[6]
[7]
[8]
[9]
c
[10]
(send
TOP: c b a
[II] (send s
'print)
'empty?)
tf
[12]
(send r 'empty?)
#t
[13]
(send r 'push!
[14]
(send s 'size)
'd)
[15]
[16]
[17]
(send s 'pop!
(send s 'pop
(send s 'print)
!
TOP: a
[18]
(send r 'print)
TOP: d
Figure 12.11
(5
+ 5*{[14-3*(12-7)]-
will
-r,
and
made up
of the
The examples
[2 + 4) + l]
15}
is
a natural
symbol
is
problem
encountered,
(3
is
it
4]
and
pushed
encountered, the
popped and the left symbol that comes off the stack is compared to
the right symbol just encountered. If they are of different types, the nesting
is not correct. You can model the arithmetic expression as a list of numbers,
stack
is
12.3 Stacks
397
Program 12.12
stack-maker
(define stack-meJ^er
(lambda
(let ((stk '()))
(lambda msg
(case (Ist msg)
((type) "stack")
(Icunbda (x)
(display x)
(display
"
"))
stk)
(newline))
(else (delegate base-object msg)))))))
Scheme
12-7
Test your program on the examples given here and on several additional tests
you
398
devise,
some
correctly
Object-Oriented Programming
12.4
Queues
queue
is
rear,
called the front. People waiting in line for service normally form a queue in
front.
the
first
first
FIFO
LIFO
lists
lists
because the
because the
last
one in
one in
is
the
is
We
first
is
called dequeuing.
enqueue
dequeue
Our
,
!
,
!
empty.
Hem
number
implementation of a queue
first
is
way we implemented
is
list,
with the
first
To dequeue an element, we essentially take the cdr of the list. To enqueue an element, we must put it at the
end of the list, so we can make a list of the element and append that onto
the end of the queue. The code for such an implementation is presented in
Program 12.13.
element of the
list
The implementation using lists as the data structure for the queue produces
the results we want, but it does it inefficiently. The trouble is that when we
enqueue an item, we use append! which must cdr down q until the last pair
and then we attach the cdr pointer to the list containing the new item. The
longer the queue, the more "expensive" it is to cdr down q to get to the last
pair. It would be better to have an implementation that could attach the new
item to the end of the queue without having to cdr down the whole queue.
,
We accomplish
this
points to a
cell
formed by (cons
12.4 Queues
is
'
When
()
'
the queue
() ),
and rear
is
cell.
used.
399
Program 12.13
queue-maker
(define queue-m8iker
(lambda
()
(lambda msg
(case (1st msg)
((type) "queue")
((empty?) (null? q)
((enqueue!) (for-ef feet-only
(let ((list-of-item (cons (2nd msg)
(if
'())))
(null? q)
(set! q list-of-item)
(append! q list-of-item)))))
(for-each
(lambda (i) (display x) (display
"
"))
q)
(newline))
(else (delegate base-object msg)))))))
has in
how
it
the
(cons 3
list.
the numbers
new item
'
()
Our new
is
and
2,
with
definition of
is
at the front.
itself to
queue-maker
is
given in
Program
12.15.
cell in
the
sample
Exercises
Exercise 12.10
Add
400
Object- Oriented
Programming
rear ^--^
(a)
\^
rear
(b)
Figure 12.14
>r
>'
>'
list
the elements
2,
1,
after invocation of
elements
3,
with
1 at
(send a 'enqueue-list
1, 2, 3, 4, 5,
if
Is
if
is
Do
Why?
Exercise 12.11
Revise the definition of queue-maker in Program 12.15 to include a message
enqueue-maoiy
(send a
'
enqueue-many
'x
number
'y
same
effect as
(begin
(send a 'enqueue! 'x)
(send a 'enqueue! 'y)
(send a 'enqueue! 'z))
queue->list
Define a procedure queue->list that takes as its argument a queue q, with
size disabled, and returns a list of the elements in q without destroying the
Exercise 12.12:
queue.
(list
the front
front
is
now
first
list,
Repeat
12.4 Queues
list,
until the
it is
at the
401
Program
12.15
queue-maier
(define queue-maker
(lambda
()
'
()
'())))
(let ((rear q)
(lambda msg
(case (1st msg)
((type) "queue")
'())))
(eq? rear q)
(length (cdr q) )
((print) (display "FRONT:
((size)
")
(f or-each
(lajnbda (x)
(display i)
(display
"
"))
(cdr q))
(newline)
(else (delegate base-object msg))))))))
When
it is
is
list
intact.
Exercise 12.13
Rework the previous problem with the method name size enabled.
402
Object-
Onented Programming
[I]
[2]
#t
(send
(send
[5] (send
[6] (send
[3]
[4]
q 'enqueue! 1)
q 'enqueue! 2)
q 'enqueue! 3)
q 'size)
3
[7]
(send q 'front)
(send q 'dequeue!)
(send q 'print)
FRONT: 2 3
[10]
[II]
Figure 12.16
Exercise 12.14
In the first version of a queue given in this section, the message
enqueue!
if
is
replaced by (append
we
implement circular lists as objects and then use them to define both the stack
and the queue, making use of delegation to take advantage of the properties
of the circular
list.
In an ordinary
list.
last
This
cons
is
cell. If,
back to the
list,
first
cell
points to the
hand
cons
cell in
the
list,
list is
empty
side of the
list
a circular
points
list.
The
403
>
marker
1
/
r
(a)
<
marker
/
r^
d
Figure 12.17
^^
-^
n^
(b)
list
and a is shown in Figure 12.17a. Note that marker is a pointer to the cons
cell whose car is a. Then to make the list circular, (cdr marker) points back
to the
whose car
cell
is c.
with d as
circular
its
To add an item d
reset the
to this circular
list,
we cons d
to
Thus
inserting d into a
nonempty
list
Similarly, to
circular
d. so
list,
we only have
to write
list in
Figure 12.17a.
404
insert
list is
Object- Onented
Programmtng
empty.
list.
list,
that
is,
is
delete
move!, which
,
!
list.
shifts the
circular
list,
number
The code
circular-list-meJcer
for
meirker
is
empty?
is
received,
it
is
empty
the
is
The message
two parts, the method
empty
consists of
list
Initially,
list,
whether msorker
tests
list.
list.
name insert! and the item to be inserted. There are two cases to consider
when
empty, we
list is
we have
make
to
back to meirker
the
list
marker
make a
have a circular
consisting of
list
to point to that
circular, so
We now
itself.
first
list
Then
list.
of meirker point
item we inserted.
On
if
the
list
is
new item
is,
We
list
list,
new
we
new head
head or a
However, we
tail.
may
And we may
of the
think of marker
itself as
list
list.
list
to be
to
make
to
cell
the
list
cell in
the
list.
If
If
the
the
list
meirker
list is
itself),
refer to the
Then we
found the
down
length on
the
list
if
received, an error
signaled.
empty
list.
Otherwise, we again
marker
is
to point to (cdr
marker)
points.
(cdr meo-ker)).
while counting.
size in
We
This requires
eflficient
way of
when we
insert or delete
have to be careful
in writing the
appropriately
We
is,
size of
is
list
the procedure
cdring
then msurker
"head" of the
When we
is
list
that
list.
we do
not get into an infinite loop, going around the circle of pointers indefinitely.
405
Program
12.18
circular-list-maker
(define circular-list-maker
(lambda
()
(size-gauge (gauge-maker
addl subl)))
(lambda msg
(case (1st msg)
'circular list")
((type)
((insert
!)
(begin
'
(head)
(if
()))
(cdr marker))))))
(null? marker)
((delete
!)
(cdr meurker))))
(for-ef feet-only
(if
(null? marker)
(begin
(send size-gauge 'donnl)
(if (eq? maurker (cdr marker))
(set
marker
'
())
(move
(for-effeet-only
(if (null? marker)
((size)
(newline)
(else (delegate base-object msg)))))))
4O6
Object-Oriented Programming
"
"))
Program 12.19
stack-maiker
(define stack-maker
(laabda
()
(lanbda nsg
(case (1st msg)
((type) "stack")
no longer
circular,
indefinitely.
We
are
now ready
of a circular
list.
marker stays
fixed.
When
the circular
list
as an
the circular
list
as a
list.
list.
The
The code
list is
insert
sends
delete! message.
is first
When
printed,
is
is
is
it
to
sent to
received
sent to the
for
stack-maker using a
circular
list is in
Program
12.19.
This
is
move
list.
The
circular
list
was
flexible
in eflficiency
cells.
The
circular
keep
in general, a useful
data
list is,
structure.
407
Program
12.20
queue-maker
(define queue-maker
(lambda
()
(lambda msg
(case (1st msg)
((type) "queue")
'move!))
(send c 'print))
Exercises
Exercise 12.15
Redefine the stack-maker and queue-maLker procedures presented in Pro-
method names
are enabled.
Exercise 12.16
Draw
list. Start with the empty stack, push on the items a, b, c, and d, and then
pop these four items. Show the box and pointer diagrams for the successive
stages as the stack increases and decreases in size.
Exercise 12.17
Make
the
ercise
same sequence
of
Exercise 12.18
Redefine circular-list-maker in Program 12.18 keeping a local variable
that
is
gauge.
initialized to zero to
Then do
it
list
without using a
Exercise 12.19
When
building a circular
Instead, the
408
list, it is
Object-Oriented Programming
rely
redefined.
a simple
return
For example,
list, it
c.
if
would be necessary to
no
and
cell c,
then using
test
was a
is
testing.
is
that
structures are built that can unintentionally enter infinite loops. Redefine
Exercise 12.20
Add
method reverse to the circular-list-maJcer that reverses the circular list in such a way that the cdr pointer of each cons cell is changed to
point to the previous cell in the list instead of the next cell. The diagram
a
in Figure 12.21
reversing.
As
shows a circular
in the
list
marker
marker
\^
i
>r
a
\
Figure 12.21
12.6 Buckets
y f
y r
Reversing a circular
>r
list
computed by procedures
by memoizing those procedures. The values were retrieved from the table by
calling a procedure lookup. In this section, we construct objects that have
In Chapter 11,
tables,
We
also present a
in
which the
409
is
bucket
is
like
flat list.
a structure
be thought of as a
An
entry in a bucket
is
associated value.
its
as in a table) consists of
two
parts:
Fibonacci procedure,
each table entry consists of the procedure's argument and the value of the
procedure when called with that argument. In our bucket, the procedure's
When we
is
if
the key
is
argument
for that
value.
update a bucket,
by
key,
is
is
determined by invoking an
is like
initializing procedure.
ous chapter for tables. In that use, we invoke (lookup key table success
fail), and in the object-oriented view, we invoke (send bucket 'lookup
if
if
there
key
is
is
is
invoked on zero
arguments.
For update! messages there
is
some
similarity with
are separate responses to the existence or nonexistence of the key in the table.
The
call
if -present proc-if-absent).
occurs.
If
key
is
If
is
replaced with
is
exist,
it is
typical session
is
an
mechanism
for
implementation of a bucket-maker.
we
Recall that
improving the
defined
memoize
efficiency of
We
can use
The key
will
(proc n).
410
Object-Oriented Programming
its
[I]
[2]
(define b (bucket-maker))
(send b 'lookup 'a (lambda (x) x) (lambda
()
'no))
no
[3]
[4]
[5]
[6]
(send b 'update! 'a (lambda (x) (addl x)) (lambda (x) 0))
(send b 'lookup 'a (leunbda (x) x) (lambda () 'no))
(send b 'update! 'a (lambda (x) (addl x)) (lambda (x) 0))
(send b 'lookup 'a (lambda (x) x) (lambda () 'no))
(leimbda (x)
Figure 12.22
()
'no)))
Exercise
Exercise 12.21
(define memoize
(lambda (proc)
(let ((bucket (bucket-meiker)))
(leuabda (arg)
we
size of
a bucket has
its
own
cost.
As
information up in the bucket gets more and more expensive. Let us consider
list
of strings, like
411
Program 12.23
bucket-maker
(define bucket-maker
(lanbda
()
(lambda msg
(case (1st msg)
((type) "bucket")
((lookup)
(let ((key (2nd msg))
(for-ef feet-only
(let ((key (2nd msg))
(lambda (pr)
(set-cdr! pr (updater (cdr pr))))
(lambda
(let ((pr (cons key (initializer key))))
(set! table (cons pr table))))))))
Program 12.24
memoize
(define memoize
(lambda (proc)
(let ((bucket (bucket-maker))
(lambda (arg)
(send bucket 'update! arg (lambda (val) val) proc)
(send bucket 'lookup
<urg
a,
an,
and
We
the
like to find
follows:
412
would
f ))))))
Object-Oriented Programming
We
(define word-frequency
(lambda (string-list)
(let
(b (bucket-maker)))
(f or-each
string-list)
b)))
list
text as a key
Now
associated value.
some
string-list
is
bound
to
text; for
...).
By
writing
we
the different words in our text as keys and the frequency of that word as
To
associated value.
"the" appear
see
in the text,
its
(map
(lambda (s)
(cons s (send word-frequency-bucket 'lookup s
(lambda (v) v)
(lambda
()
0))))
This returns a
list
7)
("an"
0)
("the"
We
10)).
different
it
would
have now seen two ways of handling the building of tables for such
first
method was
has the disadvantage that when the table gets long, lookup becomes a costly
The
other
413
entries.
We
and
way we can
a
is.
we could
use the
first
Of
buckets.
Program 12.25
is
how
is
hash-table-maker
(define hash-table-maker
(bucket--maker))) size)))
(lambda msg
(case (1st msg)
(else
An empty
bucket
is
v.
an index
is
at that index
is
key,
By
same information is
forwarded to the bucket. We now write the new definition of memoize using
a hash table in Program 12.26. In order to write this new memoize we only
need to supply arguments to hash-table-maker. Everything else remains
unchanged. This version of memoize is restricted to numerical data since
The hash
its associated hash function invokes remainder on its argument.
delegating to the bucket the original message, the
414
Object-Oriented Programming
it is
Program
memoize
12.26
(define memoize
(remainder x 1000))))
(let ((h (hash-table-maker 1000 hashf)))
(lambda (proc)
(lambda (arg)
arg (lambda (v) v) proc)
(send h 'update
Similarly
we
earlier
(lambda
#f)))))))
The code that assigns to each keyboard charAppendix Al) provides us with just the help we
Scheme has a procedure string-ref that takes a string and an inteand returns the character in the string having that integer
as its index. Scheme also has the procedure char->integer, which takes a
character as its argument and returns the integer associated with that character. We shall study the character data type more fully in Chapter 15. We
need.
ger as arguments
now
word-frequency:
(define word-frequency
(let ((naive-hash-function
(lambda (s)
(lambda (string-list)
(f or-each
string-list)
h))))
(string-ref
i)) for i =
is
to (subl
finds the
remainder with the length of the vector. The important aspect of the choice
of hash function
is
that
The advantage
can be stored
cient
it
its
of hash tables
is
that
when order
load.
is
The disadvantage
is
that
far
more
we
rely
effi-
on a
415
demonstrate
this,
in
To
(define neH-bucket-maker
(lambda
()
(hash-table-maker
is
as inefficient as a bucket.
naively.
We
Of
would never be
done. In practice, most systems discourage the user from worrying about the
size of the
Exercises
Exercise 12.22
Construct a
list
some paragraph in this section, and run wordDetermine how many of each of the articles o, an,
of strings from
list.
Exercise 12.23
Using the
list
number
Exercise 12.24
Include a message re-initialize
hash-table-maker.
in the definition of
method
bucket-maker and
its
initial state.
Exercise 12.25
Lists that
a.
Include a remove
message
in
4I6
Object-Oriented Programming
is
always
false.
(begin
(send b 'remove! key)
(send b 'lookup key (lambda (v) #t) (lambda
is
always
#f)))
false.
b. Include
and
()
its
expression above
is
always
is
false.
store!
Exercise 12.26:
Define a procedure store! that takes a hash table (or bucket), a key, and a
value and
is
defined so that
if
is
(begin
(store! b key value)
is
Do
always true.
maker
(or
this
(lambda
()
#f)))
bucket-maker).
Exercise 12.27
Include an image message in bucket-maker whose value
value pairs. Design
key, that
message.
#1))
is
update
If
is
it
is
list
of the key-
will not
mutate the
list
()
true then
is
always
false.
Exercise 12.28
Using the previous exercise, include an image message
whose value
is
list
Design
it
in
hash-table-maker
subsequent update to an existing key, that update will not mutate the
list
If
is
true,
an example where
able to use
append
if
()
#f))
is
correctly,
you should be
4^7
The next
Work them
in order
and you
will discover
Exercise 12.29:
theater-maker
is
gauge
entering a theater,
When
theater
When
may
for
is still
is
showing at the
line to
purchase
By
tickets.
ticket
using a
queue where
What are
of theater-maker? What
the
are
else clause
the disadvantages?
(define theater-maker
(lEunbda (capacity)
(let ((ticket-line ( queue -maker )
(vacancies (gauge-maker capacity addl subl)))
(lambda msg
(case (1st msg)
((type) "theater")
((enter!) (if (zero? (send vacancies 'show))
(display "doors closed")
(begin
(send ticket-line 'dequeue!)
(send vaceuicies 'down!))))
((leave!) (if (< (send vacancies 'show) capacity)
(send vacancies 'up!)
(error "leave!: The theater is empty.")))
(else (delegate ticket-line msg)))))))
Exercise 12.30
In
We
like to
we
(define theater-maker
(lambda (capacity)
(let ((ticket-line (queue-maker))
j^l8
Object-Oriented Programming
Why
must
We
delegation,
default,
first
it
tries
We
defaults. If the
message
is
single
delegation.
Program 12.27
combine
(define combine
(lambda
(f g)
(lambda msg
(let ((f-try (delegate f msg)))
(if
(delegate g msg)
f-try)))))
is
it
will delegate
it
invokes
g.
invalid-method-name-indicator.
If
line in
will
will delegate
theater-maker.
419
(define theater-maker
(lambda (capacity)
(let ((ticket-line (queue-maker))
(vacancies (gauge-maker capacity addl subl)))
(lambda msg
(case (Ist msg)
((type) "theater")
((enter!) (if (zero? (send vacancies 'show))
(display "doors closed")
(begin
(send ticket -line 'dequeue!)
(send vacancies 'down!))))
((leave!) (if (< (send vacemcies 'show) capacity)
(send vacancies 'up!)
(error "leave! The theater is empty.")))
(else (delegate (combine ticket-line vacancies) msg)))))))
Exercise 12.31
The multiple
is
some-
and
(delegate (combine vacancies ticket-line) msg)
Exercise 12.32
be disabled:
ji20
Object-Oriented Programming
(define theater-maker
(lambda (capacity)
(let ((ticket-line (queue-maker))
((type) "theater")
The next six problems are related. Work them in order, and you will discover
some interesting generalizations of objects as we have defined them in this
chapter.
Exercise 12.33
Consider a new definition of send.
Program
send
12.28
(define send
(lambda args
(let ((try (apply (car args) args)))
(if
"
(car message)
'
type)
"type."))
try))))
According to
Here
is
this
send
to build
first
mes-
counter-maker:
421
(define counter-meiker
(lambda message
(let ((self (cair message)) (msg (cdr message)))
The
variable
its cdr.
message contains the receiver as its car and the original msg as
delegate, we use the whole message. Rewrite box-maker
definition of coxmter-maker works. Be sure to redefine base-
When we
so that this
object.
Exercise 12.34
Below
is
(define cartesian-point-maker
(lambda message
(let ((self (ceur message)) (msg (cdr message)))
Fill in
[1]
[2]
[3]
[4]
7
[5]
7
[6]
7
422
Object-Oriented Programming
'distance)))
Exercise 12.35
Using the definitions of the previous exercise, we add a new kind of point.
In the Cartesian point,
In this definition,
as the
sum
the distance to the x-axis and the distance to the y-axis. This type of point
called a
is
cities.
traveled in
(p (cartesian-point -maker
x-coord y-coord)))
(Icunbda message
With
its
sum
summing
[7]
[8]
7
[9]
[10]
Exercise 12.36
(0,0).
as arguments.
Add
the
423
(define cartesi8m-origin-maker
(lambda ()
(let ((x-coord 0) (y-coord 0))
(lambda message
(let ((self (car message)) (msg (cdr message)))
(case (car msg)
((type) "Cartesian point")
((distance) (sqrt (+ (square x-coord) (squeure y-coord))))
((closer?) (< (send self 'distance) (send (2nd msg) 'distemce))'
(else (delegate base-object message))))))))
Exercise 12.37
Using the definition of your solution to cartesizin-origiii-meLker from the
previous exercise,
[1]
[2]
7
[3]
fill
in the
gaps
in the
experiment below.
[4]
7
[5]
7
[6]
Exercise 12.38
(define manhattan-origin-maker
(lambda ()
(let ((p (cartesian-origin-maker)))
(lambda message
(let ((self (car message)) (msg (cdr message)))
(case (1st msg)
((type) "M2mhat tan point")
((distance) ?
)
(else (delegate p message))))))))
424
Object-Oriented Programming
Simulation:
13
Objects in Action
13.1
Overview
One
of the
many
of real-world
uses of computers
phenomena with
is
in simulation, that
how varying
behavior
is
modeled and
mimic the
in the
is,
We
the con-
generally select
define objects
real world.
modeling
If
and actions
the real-world
experimentation.
By
We
making
in
Simulation
programming in a simulation
example because we can build a
of a gasoline station.
fairly realistic
model
We
for
it
It
also gives us
an
12,
13.2
Randomness
Simulation problems often deal with phenomena that involve uncertainty.
number
we use will have values that are generated randomly. We already used such randomly generated values when we generated
lists of numbers to be sorted in Chapter 10. We say that simulations that
of the variables that
make
Monte Carlo methods. For our gas station simulation, we describe three
different random number generators: uniform, exponential, and normal.
ing
In our gas station simulation, the customers have a choice of full service
or self-service.
We
self-
service, say,
arrives,
better
full service.
We
through
tomer wants
less
is
in the
number is
The number that
99. If that
self-service.
through 99 and
is
is
an example of a
any value
dom
in
If
the values
in that interval
is
it
takes on are
10, generates
some
is
called
fixed interval
and
Chapter
all in
is
and
1,
excluding
is
called.
but including
1,
To generate
we can use
Program
unif-rand-var-O-l
13.1
(define unif-rand-veur-O-l
(let ((big 1000000))
(lambda
(/
(+
()
1
we cannot always tell exactly when the next customer will arrive. The variable that tells us when the customers arrive is also
a random variable. It is shown in probability theory that the time between
the successive arrival of customers is a random variable with an exponential
distribution.^
(See Program 13.2.) That is, the time between the arrival of
In
an actual gas
station,
426
is
and
between
1,
is
not including
0.
We
random number.
We
to be able to take
gram
is
initialized,
minute as
its
Program
is
to be
set
when
the pro-
an integer with
smallest value.
exponential-random-variable
13.2
(lambda (mean)
(*
mean
Program
(-
(log (unif-rand-var-0-1))))))
arrival-time-generator
13.3
(define airrival-time-generator
(Ijunbda (av-arr-time)
(+
The number
variable. It
also a
random
is
or 2 gallons
some average
large quantities
buy
might
above 25 gallons.
It
purchases
mean
is
fall in
m. In
assume that
an
if
interval,
We
13.2
Randomness
4^7
and
between
1.
random
variable u,
let
us generate 12 such
m + s yj(u,- .5)
t=i
The Greek
letter
sigma,
^,
indicates that
Program
13.4
nonnal-ramdom-vaariable
(define normal-random-variable
(+ (-
(unif-rand-var-0-1) .5)
Program
mean
13.5
(*
gallons-generator
(define gallons-generator
(lambda
()
(maix 1
We always use
it
428
Exercises
Exercise 13.1
game
In the
of odds and evens, two coins are tossed. If the result of a toss
program
tail,
we
to simulate this
Otherwise, we
call it odds.
game
call it evens.
is
Write a
Exercise 13.2
While riding
in
track of the last two digits of the license plates of passing cars.
He bets you
$10 that within the next twenty cars that pass, at least two passing cars
may
This
game
last
two
will
to determine whether
bet.
or lost.
Exercise 13.3
(lambda (m a seed)
(lambda (n)
(let ((u (/ seed m)))
(set! seed (modulo (* a seed) m)
(floor (* n u))))))
()
1000))
(define random
If
(expt 7 5)
(random-time)))
your implementation of Scheme has a procedure that gives you the time
of day,
it
will suffice.
a.
1)
numbers
If not,
in that
13.2 Randomness
Generate n random
The
fraction
429
of those that
fall in
tof.
b.
Count the number of upward runs (that is, sequential runs of random
numbers in ascending order) of length k and the number of downward runs
(that is, sequential runs of random numbers in descending order) of length
Ar when a large number of random numbers is generated.
For each value of
k,
Implement these two tests in Scheme, and run them using the random
number generator defined above. If your implementation of Scheme has a
random number generator, test it too. Interpret the results.
13.3
The Gas
Station Simulation
Our simulation concerns a gasoline station that has two lanes leading to selfservice pumps and two lanes leading to full-service pumps. This is not an
uncommon configuration in small stations. To run the simulation, we specify
the following initialization parameters:
when the
clock reads
in
hours.
self-service.
prolit-sell: The
is
what
is
estimated here.
profit-full: The
full-service gas sold.
the gas
at the self-service
(e.g.,
pump
cleaning windows,
etc.).
in excess of the
pump-rate: The number of gallons of gasoline per minute that the pumps
deliver.
4S0
Gas Station
2 full-service pumps
2 self-service pumps
C\
aock
closing time
arrival time
pump queue
Dequeue customer
Dequeue customer
Update clock
Dequeue customer
Update clock
purchase data
Output
statistical
{
Update clock
and
arrival
Figure 13.6
time
The
pumps. Moving downward, we
is
served and
When
all
is
in the
still in line
is
pump
recorded.
new ones
are
are served, the statistical data for the day are printed
out.
431
station
Tf^t^r%rt
service
pump
pump
pump
wnicn serve
5lll
^ITIT^fV*?
iprvp
pump7
queue of customers
queue of customers
empty
^i/e
check
queue of customers
queue of customers
customer
>^
CTQllrtnc
^A
gallons generator
1V/VV/J.\J
service
service
nuTnV>er~of
w
wait!
max wait'
total
t r*t Q 1
counter
T^fr*Ti 1
accumulator
accumulator
accumulator
report procedure
>
rpnort
Figure 13.7
is,
other objects.
named station
created by
its
its
The pump
is
for service,
object, which
man-
Program
record.
We
13.12).
objects,
(self or full)
and the
432
(see
We
use several other objects that are created by object makers defined in
Chapter
12.
The
object
Each
arrival
pump
The
is
initial
made by queue-meiker
total
pump
at the
tally
is
customers
is
The
full),
The
we keep
number
total waiting
(3)
(2)
12.
kept by a box
is
Chapter
in
object called timer. Finally, for each type of service (self and
time for
is
customers
for all
total profit
is
is
kept in an accumulator
total-profit.
values of the eight initialization parameters are passed to the pro-
The
operand
peissed to
simulation
The management
simulation that
is
is
invoked by simulation-setupftrun.
We
of the customer through the station illustrated in the flowchart of Figure 13.6
reflected in the code for the procedure
The
is
value
bound
to the parameter
simulation, given
station
in the
in
Program
13.9.
procedure simulation
for
we
is
box aurrival stores the sum of the current clock time plus the time increment
until the next
generator.
customer
We
arrives,
enter loop
which
is
it is
it is
so created
is
enqueued to the
pump
Next, station
is
4^3
Program
13.8
simulation-setup&mn
(define simulation-setuptrvm
profit-self profit-full
extra-timeJself-pump extra-timeCfull-pump pump-rate)
(let ((self-service (service-maker "Self" profit-self))
(simulation
(station-maker
'/,-self -service
self-service
full-service
extra-timeJself-pump
extra-time8full-pump
pump-rate)
(counter -maker
addl)
av-eirr-time
(* 60
close-time)))))
pumps to check its queues. Looking at the code for pump-maker, we see
when pump is passed the message check and the queue q associated with
pump
is
finished
pump
is
reset to -1.
is
that
Whenever a customer
Thus if the timer is found
that
received,
it
is
to
to store the total time the customer at the front of the queue spends at the
pump. This
pump
by one,
is
zero.
When
From then
in
timer
on, each
is
pump
reduced
is
passed
the message check, the customer has completed what had to be done at the
434
Program
simulation
13.9
(define simulation
) ) ) )
(letrec
((loop
(lambda
()
(prepare-for-closing)
(begin
(if
(=
(begin
(send station 'which-serve
'show)
(begin
(send station 'serve)
(send clock 'update!)))
(loop)))))
(prepare-for-closing
(lambda
()
(begin
(send station 'serve)
(send clock 'update!)
(prepare-for-closing) )
) ) )
(loop)))))
2.
all
3.
the
4.
pump
and
4^5
Program
13.10
station-mcLker
(define station-maker
(send p 'check)))
(all-empty? (andmap-c (lambda (p) (send p 'empty?))))
(shorter (lambda (pi p2)
(if
(<
(which-serve)
(let
(piimp
'/.-self)
selfs
fulls))))
(send piimp 'enqueue! (2nd msg))))
When customer
we
receives the
above
Then
statistics
if
the
is
pump's queue
total
is
empty,
its
time at the
timer
pump
is
for the
customer who
is
it
now
is
at
station
serve) so clock
'
is
for
When
it
is
is
new
customer, we only pass the message serve to station and then update clock.
When clock
closing.
shows that
If at least
it is
closing time,
is
we
prepare-f or-
when
436
all
is
Finally,
passed to station.
In
Program
13.11
pump-maker
(define piunp-maker
'gallons)))
(lambda msg
(case (1st msg)
((type) "pump")
(cond
((negative?
((zero? c)
c)
(increment)))
(send q 'dequeue!)
(send customer 'record service)
(send q 'empty?)
(if
port
is
(Program
we
report
In
is
message reservice-maker
final values of
when each customer was dequeued. The procedure report, defined in Program 13.14, displays this information. We shall run the
simulation for various parameters and see how this information is displayed.
the statistics stored
We
gais
development as a programmer.
Let us
now run
the simulation.
We
call
following parameters:
437
Program
13.12
customer-maker
(define custoaer-Baker
(lambda msg
(case (1st msg)
((type) "customer")
((gallons) gallons-pumped)
((record) (let ((service (2nd msg))
(wait (- (send clock 'show) arrival-time)))
gallons-pvi^ed)))
close-time:
12 hours
'/.-self-service:
av-arr-time
profit-self
profit-full
759c
4 min.
So. 10 per gallon
So. 10 per gallon
extra-timeCself-pvimp:
5 min.
extra-timeCfull-pump: 8 min.
pump-rate: 4 gallons per min.
We
then have:
(simulation-setup&nin 12 75 4
[1]
8 4)
Self -Service:
Full-Service:
The number of customers is 37
The average wait is 13
The program
but
it
know what
438
does not have a user-friendly interface in the sense that the user must
the parameters are and the order in which to put
Program 13.13
service-maker
(define service-meiker
addl))
(total-wait (accumulator-meiker
+)
(msix-wait (accumulator-maker
max))
+)))
(leunbda msg
(report full-or-self
(send number-of 'show)
Program 13.14
report
(define report
(Ijuabda (full-or-self num-cust total-wait meuc-wait profit)
(writeln
There were no
"
"
(begin
"
(writeln
"
(writeln
"
(writeln
"
niim-cust)
"
msuc-wait)
"
profit)))))
procedure simulation-setupftrun
that
"
"
it
is
is
called.
Thus we design an
interface to
439
Program
prompt-read
13.15
(define prompt-read
(lambda (prompt)
(display prompt)
(display
")
"
(read)))
the program that will prompt the reader for the information needed to run
the simulation. For that purpose, we use the procedure prompt-read, which
prints its
read
is
in
Program
be
It
An example
13.15.
prompt-read
is
[2]
(let ((hours
(prompt-read
"Elnter the number of hours the station is open:")))
"
hours
"
hours."))
12
We
prompts that we
wcint to display.
first
We name
constructing a
this
list
list
of
all
of the
station-prompts:
(define station-prompts
'("Elnter the number of hours the station is open:"
We next
plies
prompt-read
in the order in
to each
in the list
station-simulator
440
prompt
is
list
It
and builds a
that ap-
of the responses
list
it
Program 13.16
gas-station-simulator
(define gas-station-simulator
(letrec
(lambda
(apply simulation-setupftrun (loop station-prompts)))))
(gas-station-simulator)
Enter the number of hours the station is open: 12
Enter the percentage of self-service customers: 75
Enter the average time in minutes between arrivals: 4
Enter the profit per gallon from self-service customers: .10
Enter the profit per gallon from full-service customers: .10
Enter the extra time at the pump for self-service customers: 2
Enter the extra time at the pump for full-service customers: 4
Enter the delivery rate of the pumps in gallons per minute: 4
Self-Service:
The number of customers is 110
The average wait is 6
The mciximum wait is 12
The total profit is 120.70
Full-Service:
The number of customers is 35
The average wait is 8
The mciximum wait is 10
The total profit is 44.40
[3]
Figure 13.17
We
can now use this simulation to see what happens when certain parame-
example,
We
if
75%
44i
60
110
131
192
274
Self-Service:
is
84
12
14
20
169
123.10
70.00
160.40
232.20
334.90
Full-Service:
Gas
is
was
35
40
53
86
12
11
11
17
45.70
44.40
28.10
18
66.10
100.40
service sales
22
on
self-service sales
at the
pump
for self-service
for full-
customers
full-service
with the average time in minutes between the arrival of successive customers
taken to be
When
8, 4, 3, 2,
and
1.
The
results are
is
large
summarized
in
Table 13.18.
at
the pumps, it is faster to use self-service. As the queues get longer with
more frequent arrivals, the smaller volume of full-service customers allows the
attendants to keep the waiting time relatively short, whereas the self-service
customers pile up and ultimately take hours to get out. Although a wait of
more than an hour is generally considered intolerable, there were times during
the oil crisis of 1978 when people did stay for hours in gas station queues which
extended for blocks around the station. In normal times, the station would
and a
full service.
summary
larger percentage of
It is
the screen a picture of the cars entering and advancing through the queues,
as well as the current values of the variables. There are
in
442
many
creative
ways
in this text.
Exercises
Exercise 13.4
Write a simulation of the following experiment.
record
die
kept of
is
is
Two
possible
on
to 6
sum comes
its faces,
thrown n times.
dice are
sums
sum
column and the percentage of times that sum came up in the second
column. Run the experiment with n taking the values 100, 200, 400, and 800.
in the first
To record
the results of each toss, use 11 counters (as defined in Section 12.2.3),
one for each possible face sum, and increment the counter each time that
sum
appears.
Compare your
which
are 2.78%, 5.56%, 8.33%, 11.11%, 13.89%, 16.67%, 13.89%, 11.11%, 8.33%,
5.56%, and 2.78%. These are easily found by counting the number of ways a
given face
dice can
sum can be
come
up),
six ways, so
We can
a
and multiplying by
x 100%
Exercise 13.5:
100.
16.67%.
Estimation of
tt
use simulation to
circle of radius 1
tt.
We
this
board
is
likely to
We
feet.
fact that
game.
The area
is
equally
if
it falls
number) and
We
of this
large
we use the
If
of these throws
fall
times (iV a
we would
to
1 and
1.
the experiment
distributed
counts
is
random
how many
of
them
N=
and y as uniformly
between 1 and 1; and
tt.
+ y^ <
Run
1.
The program
and 100000.
Exercise 13.6
The
fewer than or
shorter
definition of
in
44^
Figure 13.19
for estimating
tt
and any other procedures so that the simulation supports arbitrary numbers
of
pumps
Exercise 13.7
the
results
to a case
full service.
Run
in the tables.
Exercise 13.8
The gas
if
make
pump
we might hope.
their diesel fuel?
argument
list
of
kind of
fuel,
if
prompt -read
Exercise 13.9:
(lambda items
"
")
(read)))
Can
this definition
be used
Program 13.15?
444
in place of
is it
better than
Exercise 13.10
In
Program
but
it
13.16, the
gas-station-simulator prompts
does not echo that data back to be sure that the correct data was
entered.
For example, when the response to the prompt "Enter the number
is
simulator so that
is
open:"
is
12,
prompt.
Exercise 13.11
Add
line that
Exercise 13.12
Exercise 13.13
Explain why the following definition of gas-station-simulator can not be
used in place of Program 13.16:
(define gas-station-simulator
(lambda
()
44^
Part 4
is
little
Ordering
cafe in Paris.
it
is
may
in French.
1.
The
If
table, for
the menu:
Poulet
"chicken,"
is
looking up
rati.
First
all
is
analogous to
roti
and
it is
is full
"baked." So you
know
it
is
that
it
However, with your dictionary, you can look up each word and translate the
entire
menu
words
in a foreign language.
let
in
When you
Derived
do not know
lambda
expressions.
Suppose that you do not have a dictionary but your Parisian waiter and
you know a
bit of
he does not
know how
poulet roti
is,
it
in
into something
first
translated into
let
lambda expressions
mechanisms for inserting
let
different
These
Most of the
finite list-processing
replacing finite
is
Working with
).
If
such a
is
44^
to convince
onto
seen circular
car
lists,
list
list,
lists
the task
about
lists
would be
1, its
empty
and consing
is
lists.
virtually complete.
those
unbounded
lists
in this chapter,
does exist.
cdr would be (2 3
),
remains
14
14.1
Overview
In Scheme, operators are applied to their operands by enclosing the operator
followed by
its
operator to
its
operands
operands
in parentheses.
such an application
is
operand
We
is
applying an
is:
(.operator
When
The
is
following the keyword are treated differently from the operands of a procedure.
it
its
if,
Some
own.
easier to read
lambda,
of
programs, for
One
add new
Scheme
is
that
special forms to
it is
make
an
the
We
shall study
two mechanisms
for
making such
rely on an order of evaluation are said to be ill formed. Since the order
implementation dependent, such programs are not portable, and they can
not, in general, be transferred from one implementation to another.
^
Programs that
of evaluation
is
lists
all
Scheme expression
in
keyword.
When
all
such
lists
such
is
all
Each trans-
is
time to evaluate
lists.
In this
which
list
have occurred.
Form
procedures.
In fact,
it
is
them
as
we
We
is
the syntax.
If
we write
(define sm (+
We
4))
450
it
knows.
the expression (+ 3 4)
evaluated and
is
sm.
its
One way
of doing this
is
is
bound
to the variable
(+3
value
sm but
We
(+3
4)
could then
write
(define sm (laabda
The body
sion
is
of a
(+34)))
()
lambda expression
applied to
its
has no arguments,
is
it is
it
by enclosing sm
bound
is
in parentheses, that
is,
by writing (sm).
4))
invoke
(+3
when applied
its
It
we need
it
we can
We are
thus
by making
it
(define freeze
(lambda (expr)
(lambda
Then we would
()
expr)))
write:
operand (+ 3 4)
is
is
evaluated.
evaluated.
until
sm
is
called.
What happened
procedure;
it
is
when sm
is
is
for
which
that (+ 3 4)
called.
is
evaluated during
if it is
to accomplish
what we want.
To
We
form with keyword macro.
expr) and to transform into the thunk (lambda
^
we make use of a
special
At the time this book is being written, the Scheme community has not yet agreed upon a
standard way of declaring specied forms. In this book, we use two methods that have been
^
Form
4^1
We
call the
macro
is
expr)
()
sponding macroexpansion.
When
an expression
is
checked to see
if it
macrocode
(in
is
first
is
subexpression
If it
is,
is
then the
macroexpansion. Then at run time, the computer sees only the macroexpan-
we had written the macroexpansion into the program instead of the macrocode. Thus the subexpression expr
of the special form (freeze expr) was not evaluated when the procedure (or
thunk) was created by evaluating (lambda () expr).
(lambda
sion
How
is
()
if
We
that literally transforms the macrocode into the macroexpansion of that code.
its
macroexpansion
expression: the
Thus we can
is
list
for the
it
macroexpansion. In our
list
case, the
make up a lambda
of arguments,
(define freeze-transfomer
(lambda (code)
(make-lambda-ezpression
where make-lambda-expression
this case,
list
is
it is
the
empty
list)
'()
is
and a
lambda-expression
is
the
list
(+ 3 4).
in the
We
it
is
macrocode
define
make-
to be:
(define make-lambda-ezpression
included in some implementations. These methods use special forms with keywords macro
and ertend-syntax. If these are not implemented in the version you are using, read the
manual
for
your implementation to see how it declares special forms, and use that method
is agreed upon, code including user-made special forms
452
not portable.
Now
special
as follows:
We
if
macro places
it
"the
is
macro freeze."
We
in defining the
macro
we can
(make-lambda-expression
replace
'()
by the body of
arguments to
its
its
(lambda (code)
(cons 'lambda (cons '()
Finally, replacing
freeze-transf ormer by
Program
freeze
14.1
its
lambda expression
gives us
(lambda (code)
(cons
'
Form
4^^
version using the helping procedures or this final self-contained version declares the
14.3
find
more convenient.
Macros
In general, the special form with keyword macro has the syntax
(macro
name transformer)
where name
is
transformer
is
new
special
is
the keyword,
and
(lambda (code)
(cons 'lambda (cons
is
the transformer.
'
()
Thus we summarize by
recalling that
when a program
the program
would
let
when
entered,
the macrocode
expansion that
is
seen
when
run.
is
It is this
is
also be
()
we would
like
freeze
where the
means one
or
is
finite
number
of expres-
thingi thing2
454
of thing, whereas
This
is
it
contains the ellipsis and the special form macro will not
itself since it
know
what to do with it. Using a similar notation, we can say that a pattern
the macroexpansion is:
(lambda
()
for
first
pattern
is
to be
expanded into
is:
)=
(lambda
expri expr2
()
The symbol = can be read "macro expands to." We call a statement that has
the macro pattern on the left and the expansion pattern on the right a syntax
table entry.
In
any actual
macrocode
case, the
is
list
it.
If
we represent
macrocode by the variable code again, then (cdr code) is just a list of
the expressions that make up the body of the lambda expression into which the
macrocode is expanded. The f reeze-transf ormer procedure defined above
this
it
of freeze:
(lambda (code)
(make-lambda-expression
It
would be convenient
if
'
()
(cdr code))))
Scheme were
to have a
sides
of the syntax table entry and declare the special form for us. In essence, the
Here
is
to declare
Kohlbecker, 1986).
it
It
(see
if
(extend-syntax (macro)
((macro name transformer)
(let {(t transformer))
(extend-syntax (name)
(x ((with ((h 'with)) w) ((v
(t
'x))) v))))))
14.3 Macros
455
Program
freeze
14.2
(extend-syntax (freeze)
exprl expr2 ...)))
Since no standard
way
of
making
we shall
using macro and extend-syntax
that
is,
is
its
value.
is
defined
as follows:
thaw
Progriin 14.3
(define thav
(lambda (thunk)
(thunk)))
To show how
it is
used,
we
define:
(define th (freeze (display "A random number is: ") (ramdom 10)))
(thaw th) =^* A random number is: 7
(thaw th)
=^
is
is
it
first
time
advantageous
456
if
the
it is
is
called
calculation
is
and thereafter
same long
it
This would be
Program
make-promise, force
14.4
(value-tag "-->"))
(lambda (arg)
(eq? (car arg) delayed-1:ag))
(begin
(set-car
arg value--tag)
(set-cdr
(cdr arg))))
is
called
and the
result
obtained
is
and on subsequent
first
time
called
it is
We
We
declare
the special form delay to postpone the evaluation by creating a promise, and
is
first
When
sion
is
following:
and
it
=>
=^
=^
6
6
where make-promise
is
force's argument
promise
is
(random 10)))
The syntax
")
is
delay
it is
forced from
now
is
= (make-promise
on.
its
argument and
obtained by thawing the promise's thunk. In any event, the value stored in
14.3 Macros
457
the fulfillment
is
Program
returned.
14.4
is
We
It
..))
As
before,
Program
14.5
delay
Program
14.6
delay
(define delay-transformer
(lambda (code)
(list 'make-promise (cons 'freeze (cdr code)))))
As we have
Scheme
first
We
passed to the procedure "by value." In some languages, arguments are passed
to procedures as
if
they were thunks, and they are not thawed until they are
actually used in the procedure. Such arguments are said to be passed to the
We can write
458
is
programs
in
Scheme
an oversimplification.
so that procedures
when they
to procedures as promises, which are not forced until they are needed in the
need."
we
shall
by need.
We
have been using the special form with keyword let, which has the
syntax^
expri expr2
The syntax
...)
is
The
declaration of let
Program
as in
Program
is
now
a simple matter
val ...)
when we
use
extend-syntax
14.7.
14.7
let
(extend-syntax (let)
((let ((vaur val) ...) expri expr2 ...)
(danbda (var
To
of a
...)
lambda
we have
we need
its
parameter
list
list
list
and
its
its
operands.
body
of parameters
is
list
For the
expressions.
built
We
up by
If
first
extract the
^ When using user- declaired macros that have the same keywords cis special forms in Scheme,
you might want to avoid collisions with the built-in forms. We suggest that you siuround
the keywords of those you declaire with equed signs; e.g., =let= in place of let.
14.3 Macros
459
(define iiike-li8t-of-paraeters
(laabda (code)
(ap
Similarly,
2nd of each
pair.
list
This leads
to:
(define Beike-list-of-operands
(lambda (code)
(nap 2nd (2nd code))))
list
body
of the
lambda expression we
are building
is
(cddr code)))
With
declare
it
Program
as the
macro
14.8
let
for let.
(lambda (code)
(cons (make-laabda-expression
(nake-list-of-paraaeters code)
(make-list-of-body-items code))
(aike-list-of -operands code))))
This
is
macro let
since there
is
also
syntajc to declare a macro. Exercise 14.6 at the end of this section suggests
460
let
we use macro
pairs. If
On
we must
transformer to determine
explicitly include
the syntax
if
is
correct.
the other hand, one of the great advantages of using ext end-syntax
that
it
You may
own
is
tests
find
instructive to enter
it
We
observed that in a
let
var
whose value
in val
be bound to var
refers to
is
...)
expri expT2
,
.
cannot contain
macroexpansion,
((lambda (var
we
will
val ...)
for
recursive scope.
(letrec
(.{var val)
is
if
...)
expri expr2
for
letrec. Again,
Program
14.9
any of the
macro
it is
in var. Let us
now
write the
letrec
var val)
is
expression:
14.3 Macros
461
(define odd?
(letrec
((even? (lambda (n) (if (zero? n) #t (odd? (subl n)))))
(odd? (lambda (n) (if (zero? n) #f (even? (subl n))))))
odd?))
It
macroexpands
(define odd?
(let ((even? "any")
(odd? "any"))
(begin
(set! even? (lambda (n)
(set! odd? (lambda (n)
odd?))
how
how we
to declare
We
first
consider
construct the pairs of the form (var "ajiy"), which are in the
After
we
let
the macrocode, we use map to give us the desired pairs of the form (var
set!
expressions,
Program 14.10
and
finally,
we build a
list
Program
14.10,
letrec
(macro letrec
(lambda (code)
(cons 'let
(cons (map (lambda (z) (list (1st z) "any")) (2nd code))
(
append
(map (lambda (z)
(2nd code))
(cddr code))))))
is
How-
The syntax
462
cycle
is
Program
cycle-proc
14.11
(define cycle-proc
(lambda (th)
(letrec ((loop (lambda
(thaw th)
(loop))))
(loop))))
where cycle-proc
Program
defined in
is
In Chapter 17,
14.11.
we
shall
The last special form that we discuss has keyword or. First why must or
be a macro instead of a procedure? When we write (or ei 62), the first
subexpression ei
is
only then
is false,
evaluated, and
if it is
true,
is
then
its
value
is
returned. If ei
is
or.
The
first is false
second
(>
(/
10 x)
2))
and be sure that division by zero does not occur because the second subexpression
is
not evaluated
if
is
zero.
Thus we want or
to be a
macro that
no subexpressions,
of no subexpressions,
it
If
or
is
several subexpressions:
(or ei 62 ...)
(if ei ei
evaluates ei and
first
ei in the consequent. If ei
is false, it
(or 62 ...))
if it is
true,
it
"recursive" value obtained for the alternative. This looks like recursion, but
(if e
We
as
e,
We
is
if
ciently since
14.3 Macros
if
ei
is
true,
it
it
effi-
in the consequent.
463
some
If Ci
includes
that
is
let
We
generally incorrect.
(or ex 62 ...)
can avoid
this
insteeid of once,
and
it
in the following
program:
We
expression
is
when
the
program
is
entered, the or
expanded into
#f because the
is
leist
the scope of the nearest binding, and unfortunately the variable val was also
used in the
let
ways of avoiding
frozen entity
when
is
this capturing.
thawed,
is
it
takes a
list
of thunks as
its
We
shall
make
We first
them
of or-proc:
Progrgun 14.12
or-proc
(define or-proc
(lambda (th-lis.t)
(cond
454
when a
is
the definition
In this version, the thunks are not evaluated until they are thawed, so only
is
is
obtained.
The
remain unevaluated.
With
this definition of
becomes:
(or e ...)
How
entry?
Program
14.13
e)
...))
this
or
(lambda (code)
(list 'or-proc
(cons 'list
(map (lambda (e)
(cdr code))))))
We can
also use
We
Program 14.14
or
have:
(extend-syntax (or)
((or e ...)
Several
more
own
The
ability to
14.3 Macros
special forms in
465
Exercises
Exercise 14-1
What
is
the output of
What
is
(b c))))
the output of
What
'
(* a
b)))
general statement can you conclude from these examples concerning the
is
Some
its
macroexpansion.
Exercise 14-2
Declare the letrec macro using ext end- sjrnt ax without using let in
its
macro-
expansion.
Exercise 14-3
Consider the declaration of the macro or, below. Does this declaration suffer
the variable capturing that
we were able
to avoid using
or-proc and a
list
of
thunks?
(extend-syntai (or)
((or) f)
((or e) e)
((or el e2 ...)
Exercise 14 4'
smd
If called
it
like or,
with no subexpressions,
may
it
is
take any
true.
it is
(and t)
(and f)
(and #t #t t)
(and #t t #f)
466
number
If all
false.
of
its
Test
Exercise 14-5
The
let
expression
(y x))
y))
local
its
value
(y x))
y)
The
value 3
is
If
let
expression
is
let
expression
in (y x) to refer to the x in
as follows:
=*
y)))
10
(.var2
vo/2)
instances of vari in val^ and instances of var^ or var2 in vals cannot refer
to vari or var2 in this let expression but
environment. However,
if
we were
must
first
instances of vari or var2 in vals can refer to the f ari or i'ar2 of the preceding
two binding
It
pairs.
We
in Section 10.2.5.
has a syntax similar to that of let but behaves as though the successive
14.3 Macros
is
let
the
expressions. In fact,
same
if
there
is
as let, so that
467
)=
and
there
if
is
(let
ivaT2 val2)
pair,
...)
it
on
the following:
(let* ((a
(b
1)
(+ a 2))
(c
(* a
b)))
(+ a (- c b)))
Exercise I4.6
The procedure let-transformer is correct only if the user obeys let's syntax.
The special form let expects a list of n 2 elements. The first must be the
-f-
first
list
is
list
of two
>
(d
3)
(let ((3 3)
(let
(d
3)
(y 4)))
(y 4))
(* x y))
(y 4 5))
(* i y))
(let X 3 (* I y))
(let (("i" 3)
(y 4))
(*
"i" y))
shown below, are given to the user of let. Test these examples by invoking
let-tremsf ormer on the individual lists in question:
(y 4))
(* x y)))
=>
(y 4))
(* x y))
(* x y))
468
(* i y))
(*
"x" y))
Exercise 14.7
The
error information
where the error occurred. Redesign the information displayed so that you can
better determine where the error occurred.
named let
Exercise 14-8:
case of the
named
let.
...)
((letrec
(lambda
(,inam,e
(.var
...)
expri expr2
))
name)
val
Do
named-
let.
Exercise 14-9:
cycle
while
Exercise 14-10:
The special form while is a control structure common to many programming languages. In while, an expression is evaluated repeatedly as long as a
given condition
illustrated
is
true.
We
can
efi"ect
to 100:
(sum 0))
()
(if (positive? n)
(begin
(set! sum (+ sum n))
(set
n (subl n)
(loop))))))
(loop)
sum))
We
would
like to
14.3 Macros
eis:
469
(sum 0))
(while (positive? n)
(set! sum (+ sum n))
(set! n (subl n)))
sum)
table entry:
(letrec
((loop (lambda
()
(loop))))))
...
(loop))
... in
is
You must
the macroexpansion.
The syntax
table entry
test expri
expr2
(while-proc (freeze
where while-proc
is
defined in
test)
)
(freeze expri expT2 ...))
Program
11.8.
program.
Exercise 14-11:
The
special
sion.
Then
repeat
It
executes the
first
expres-
much
same
way as while from the previous exercise. Define repeat -transformer or
declare repeat using ext end-syntax by including while in its macroexpansion. Then redo the exercise without using while. Finally, write an expression
using repeat that models the test program of the previous exercise.
sion terminates with an unspecified value. If not,
Exercise 14.12:
it
repeats in
for
470
the
Such ex-
The
for expression
is
Then
ized to initial.
terminate.
is
the test
If test is true, it
is
is
does terminate.
If test is false,
is initialit
should
then expr
repeats.
This solution
is
of a vector:
(define vector-siim
(lambda (v)
(let ((n (vector-length v))
(sum 0))
(for i
(addl i) (= i n) (set! sum (+ sum (vector-ref v i))))
sum)))
Exercise 14.13:
The
special
do
expri expr2
exit2
((letrec
((loop (lambda
(cond
(.var
...)
{test exiti
exit2
loop)
initial
The
variable
14.3 Macros
and
it
must not be
free in test,
471
exiti exit^
.
.
, and step
expri expr2
beginO
Exercise 14.14'
(beginO ei 62 63
beginO evaluates
ating the
first
its
one.
(beginO-proc
(freeze
ei
62
63
...))
Why
[Hint:
incorrect?
=
=
e)
Read the
is
What
specification carefully.
begin
Define begin-transf ormer or declare begin using extend-syntax without
using freeze or the implied begin associated with lambda expressions.
Exercise 14-15:
Exercise I4.I6:
cond
Consider cond expressions that are restricted to including at least one expres-
an
else clause.
into nested
if
last clause
must be
(cond (else
ei
62
...))
(cond {test ei 62
(begin
62
ei
clauses
..)
Redefine member-trace and factorial below, using just the syntax table
entry for cond expressions.
4 72
(define member-trace
(lambda (item Is)
(cond
((null? Is) (writeln "no") #f)
((equal? (car Is) item) (writeln "yes") #t)
(else (writeln "maybe") (member-trace item (cdr Is))))))
(define factorial
(lambda (n)
(cond
((zero? n) 1)
n (factorial (subl n)))))))
(else
Exercise 14-17:
cond
case,
it
includes the
symbol else.
Fill in
Exercise 14-18:
))
variable-case
is
be any expression,
it is
its first
operand to
we can
write:
((2468)
((13
5 7 9)
(variable-case x
((2 4 6 8)
((13
(writeln "even") x)
5 7 9)
(writeln "odd") x)
14.3 Macros
473
Complete the declaration of variable-case presented below, and then define vaxiable-case-transf ormer. Explain why keys has been transformed
Remember
list.
...)
Exercise 14.19
If
first
Given
extend-syntax. Hint:
its synteix
If
this
you
to be taken literally.
Test
((13
Exercise 14-20:
In Chapter 12
object-maker
we presented a
set
had a
maker includes
Design a special form object-maker that abstracts this pattern of use. Are
there other patterns of use with object makers that can be abstracted?
4 74
Using Streams
15
15.1
Overview
In this chapter,
we
in particular,
brief
In Chapter 14,
we discussed the
special
is
it
is
Thus
and the
needed.
its
how we
its
evaluation.
how
list
number,
by
say,
long the
list
has to be.
between 2 and
member
12, inclusively.
We
We
shall
effect of
now
see
lists.
list
of
random numbers,
of the
Thus, the
list
list
being a
random
can be generated
(define random-2-to-12-list
(lambda (n)
(if (zero? n)
'()
Then when (random-2-to-12-list 100) is called, a list of 100 random numbers is created. Suppose we now add the numbers from the beginning of the
list until the first time the number 7 is reached, at which time the sum is
printed along with the number of integers summed. The following program
does
this:
((local-sum
(lambda (rl sum count)
(if (null? rl)
(writeln
"A seven nas not found; sum = "
sum
"
and count =
"
count)
(writeln "sum =
"
sum
"
nhen count =
"
coiint)
(local-sum
(cdr rl)
(+ next Slim)
(addl count))))))))
(lambda (rand-list)
(local-sum rand-list
0))))
sum
=31
[2]
when count = 4
When we
j^16
Using Streams
printed.
Is
But a
list
there any
of 100
way
to
create a
list
We
it.
random number
will
not be
it?
This
second operand
called, its
is
a delayed
and (fib
list
We
list.
is
We
delayed.
illustrate this
list
so that
method
of producing
9):
(define del-list
(cons (fib 8)
now
is
first
delayed-list-car, which
is
the
same
car.
Our goal
lists.
as car, since
(lambda (x)
(car x)))
Observe that
Program
this definition
15.1
delayed-list-car
we
call
(cons (fib 9)
If
(delay '()))
to this delayed
list,
34
is
returned.
we
define
delayed-list-cdr
We
and then
to be that
477
(define delayed-list-cdr
(lambda (x)
(force (cdr x))))
more compactly,
or,
Program
15.2
Then we can
delayed-list-cdr
del-list by
call is
made, 34
is
effect of
delay, (fib 9)
is
is
stored.
calling:
== 34
evaluated the
first
time
the call
(delay '())).
we apply delayed-list-cdr to del-list and then apply delayed-listresult, we get the list
(), which we call the-null-delayed-list.
test for the-null-delayed-list with the predicate delayed-list-null?
If
cdr to that
We
'
defined as
(define delayed-list-null?
(lambda (delayed-list)
(null? delayed-list)))
We
Program
15.3
lists
ceir)
478
Using Streams
Program
15.3.
call
ate their operands before passing their values to the procedure defeats the
We
can declare
it
14.
del-list
as
(define del-list
(delayed-list-cons
(fib 8)
(delayed-list-cons
(fib 9)
the-null-delayed-list) )
lists
lists.
delayed-list-cons
Program
15.4
to give us
We
can also
new constructor
random-delayed-list:
random-delayed-list
(define random-delayed-list
(lambda (n)
(if (zero? n)
the-null-delayed-list
(delayed-list-cons
(+ 2
(random 11))
We now
lists
as
follows:
4'79
(letrec
((local-sum
(lanbda (delayed-list sun count)
(if (delayed-list-null? delayed-list)
(writeln
"A seven was not found; sum = "
sum
"
and count =
"
count)
(= next 7)
(writeln "sum =
"
s\im "
when count =
"
count)
(local-sum
(delayed-list-cdr delayed-list)
(+ next sum)
(addl count))))))))
(lambda (rand-delayed-list)
(local-sum rand-delayed-list
0))))
The output from this procedure has the same form as that of our previous
version, but now a random number is computed only when it is used.
In order to see the elements of a delayed
list,
it
is
convenient to have a
list
of
its
list
delayed-list
elements:
(define delayed-list->list
(lEunbda (delayed-list)
We
delayed-list 20):
(delayed-list->list (random-delayed-list 20))
[1]
(7 5
[2]
(2
11 3 7 5 8 10 5 8 8 2 2 12 9 7 12 4 5 6)
43473995
10
44
12
777
11
55
3)
[3]
[4]
(delayed-list->list rdelayed-list20)
(7 5 11 3 7 5 8 10 5 8 8 2 2 12 9 7 12 4 5 6)
[5]
(delayed-list->list rdelayed-list20)
(7 5 11 3 7 5 8 10 5 8 8 2 2 12 9 7 12 4 5 6)
480
Using Streams
list
(random-
Exercises
Exercise 15.1
Define the delayed
list
consisting of the
first
list
consisting of the
first
list->delayed-list
Define a procedure list->delayed-list that takes a
0.
1.
Exercise 15.2:
delayed
list
list.
list
This procedure
its
argument and
is
delayed-list-sum, delayed-list-product
Exercise 15.3:
delayed
list
than
add them
k,
as
all.
Do
same
the
for
the delayed
If
first
list
k elements in a
list
evaluates to
0,
its
arguments.
the value
If
one of the
list.
Exercise 15.4
Delayed
tors.
lists
if
the-null-delayed-list,
delayed-list-null?,
delayed-list-car,
delayed-list-cdr,
delayed-list-cons.
One
alternative
way
is
still
all
be defined:
cell.
delayed-list-cons becomes:
(delayed-list-cons val
How must
del-list)
Program
(delay del-Hat))
15.3 be changed?
Does
the behavior of any of the procedures defined in this section change using
these definitions of the five basic entities? Discuss the behavior of
del-list
481
if
In particular, discuss
when (fib
8)
and
entities?
15.3
Streams
In the delayed
list
rdelayed-list defined by
(delayed-list-car rdelayed-list)
matter how long the delayed
Thus
still
list is
When delayed-list-cdr
done.
it is
is
random number.
is
It really
no further calculation
does not
how much
list is
is
returned.
of the delayed
list
may
be
When
list,
we
a stream.
what appears
We
is
omitted
to be a nonterminating
list,
or
what we can
call
lists.
in order to
We
and give them new names when they are used with
streams. The new names are stream-car, stream-cdr, and stream-cons.
their use to delayed lists
The
definitions of
in
Program
(macro stream-cons
(lambda (code)
(if (not (= (length code) 3))
482
Using Streams
15.5.
is:^
The
Program
stream-car, streeun-cdr
15.5
(define streaun-car
ceur)
Now we
Program
We
get:
random-stream-generator
15.6
(define random-stream-generator
(lambda
()
(stream-cons (+
and
Program
random- stream
15.7
This looks as though the code for random-stream-generator contains a nonterminating recursion and
its
stream-generator,
stead
is
voked, a
it
when stream-cons
is
in-
waiting to be forced.
random
integer
invoked, a stream
is
is
a cons
is
cell
refers to
stream-car
is
call,
carrying
defined recursively to be
to a delayed stream.
(or infinite)
common value
is
is
the-null-stream,
all
15.3 Streams
483
Program
the-null-stream
15.8
(define the-null-stream
Program
list->stream
15.9
(define list->stream
(lambda (Is)
(null? Is)
(if
the-null-stream
(stream-cons (car Is) (list->stream (cdr Is))))))
Program
15.10
end-of-stream?
(define end-of-stream?
(lambda (z)
(eq? X the-end-of-stream-tag)))
We
use
the-null-stream
converts any
list
(see
Program
which
list->stream is given a
circular
list,
is
an
infinite stream.
For example,
A stream
on
it
is
2 3)))
if it
(append! x x)))
a stream
is
an example of a
finite
stream.
We
list
that
is
converted into
finite
gument
484
is
the-null-stream.
Using Streams
its ar-
Program
15.11
streajn-null?
To look
Program
15.12
streain->list, f inite-streani->list
(define streani->list
(lambda (strm n)
(if (or (zero? n)
(stream-null? strm))
'()
f inite-stream->list
(lambda
(f
inite-strm)
(stream->list
We
f inite-strm
-1)))
generator:
[1]
(7 5 5 4 6 4 5 11 2 11
[2]
11 7 5 11
11 8 9 3 5 10 4 12 7 7 10)
(8 5 10 12 10 8 2 8 3 5 4 9 2 5 4 12 6 3 7 5 12 3 12 2 9)
[3]
(7
[4]
7956823567
10 12
33
11
544
5)
(7 7 9 5 6 8 2 3 5 6 7 10 12 3 3 11 5 4 4 5 10 11
We
see that
dom
random-stream (Program
12 8 4)
ent stream of
it is
differ-
called.
Other streams can be defined using stream-cons. For example, the stream
of positive integers can be defined as:
15.3 Streams
4^5
Program
15.13
positive-integers
(define positive-integers
(letrec
(
(stream-builder
(lambda (x)
(stream-builder
The stream
1 ) )
Program 15.14
even-positive-integers
(define even-positive-integers
(letrec
(
(streun-builder
(lambda (x)
(stream-builder 2)))
Program
15.15
poHers-of-2
(define powers-of-2
(letrec
(
(stream-builder
(lambda (x)
(streeim-cons x (stream-builder (* x 2))))))
(stream-builder 1)))
The
We
common features
that lead us to
seed.
The
define a procedure
is
in the
procedure in the
last line,
486
Using Streams
is
the
Program 15.16
build-stream
(define build-strean
(leonbda (seed proc)
(letrec
(
(strejuB-builder
(lanbda (x)
(stream-builder seed)
) )
x.
We
call this
(build-stream
addl))
(define even-positive-integers
(build-stream
(define powers-of-2
(build-stream
and the stream of random numbers defined above can be defined using build-
transition procedure
is
(define random-streeun-generator
(lambda
With a
of factorials.
To do
parameters.
We
15.3 Streams
so,
we
have:
487
Program 15.17
factorials
(define factorials
(letrec
(
(stream-builder
(lambda (x n)
(stream-builder
1)))
Certain of the procedures that were defined in the previous section for delayed
lists
sums the
numbers
is
first
If
a stream of
of the
end. Always be sure operations will terminate before applying them to infinite
streams.
From a
procedure proc
is
Program 15.18
new stream,
defined by
is
stream-map
the-null-stream
(stream -cons
(proc (stream-car strm)
Program
Now
let
infinite
15.19.
let
infinite streams,
Using Streams
let
an be the nth
488
and
is
is
a procedure
Program
odd-positive-integers
15.19
(proc a^ b^) as
its
that applies proc to the corresponding elements of the two infinite streams
Program 15.20
is
called
stream-apply-to-both
(define stream-apply-to-both
(lambda (proc)
(letrec
(
(str-app
(stream-cons
(proc (streeun-car si)
(stream-car s2))
Program
15.21
stream-plus, stream-times
Program
we
15.22,
define a procedure
(define odd-positive-integers
((stream-filter-out even?)
positive-integers)
15.3 Streams
489
Program 15.22
stream-f ilter-out
(lambda (test? )
(letrec
(
(helper
(lambda (strm)
((a (streaa-car strm)))
(let
(if
(test? a)
helper)))
Program 15.23
positive-integers
(define positive-integers
(stream-cons
For
if
we add
2.
Then stream-consing
we
We
integers.
first
can also
stream-
cons
integers.
if
list
first
list
list
factorials can be
shown below
are multiplied
we reproduce
of factorials
element missing.
24
120
720
...
...
24
120
720
5040
multiply
490
Using Streams
The stream
Program 15.24
factorials
(define factorials
(stream-cons
In a similar way,
left,
the resulting
without the
list is
again the
two numbers
first
and
list
1.
112
112
13
...
13
21
...
13
21
34
...
add
2
The
definition of the
Program 15.25
(define
is
then:
f ibonacci-numbers
f ibonacci-numbers
(stre<un-cons
(streaun-cons
(stream-plus
f ibonacci-numbers
(strecun-cdr f ibonacci-numbers))))
prime number
factors.
Thus
is
2, 3, 5, 7, 11,
first six
and
call it
Now
First, write
base,
take the
the base.
We
remove
first
Once
1,
all
and
itself as
primes. Eratosthenes,
way of finding
list
of
all
all
who
of the primes
again, remove
all
(in
remaining number that follows the preceding base, and then removing
multiples of the
15.3 Streams
new base
new
all
491
Program
15.26
(define divides-by
(leunbda (n)
(lambda (k)
(zero? (remainder k ci)))))
((primes
(lambda (s)
(stream-cons
(stream-car s)
(primes ((sieve (stream-car s))
(stream--cdr s)))))))
no more numbers to take as the base. The remaining numbers are the primes
less
all
of the primes
is
up
to 20.
Each successive
list is
It is
the result
(2 3 4 5 6 7 8 9 10 11
12 13 14 15 16 17 18 19 20)
17
13
15
19)
11
13
17
19)
(23579
(2357
The
11
primes up to 20.
sieve process
is
an application of a
filter
to the stream of
remaining integers that removes those numbers that are multiples of the
base.
Such a
in
filter,
Program
which we
call
beise
15.26.
In Program 15.27 we show another way of defining the stream of all prime
numbers that combines the ideas of Exercise 7.20 and the data recursion used
in Program 15.23. Instead of testing with all odd integers < t/n, we now can
restrict our testing to the odd prime numbers < -y/n. Assuming we have the
stream odd-primes, we first define a divisibility test has-prime-divisor?
which returns #t if its operand, an odd number, has a prime divisor. Then
492
Using Streams
Program 15.27
has-prime-divisor?, prime-numbers
(define has-prime-divisor?
(lajnbda (n)
(let
(max-value (sqrt n)
(letrec
((try (lambda (primes)
(and (<= (stream-car primes) max-value)
(or (zero? (remainder n (streeun-car primes)))
(try
(stream-cdr primes)))))))
(try odd-primes)))))
(odd-primes-builder 5)))
(define odd-primes-builder
(lambda (n)
(if (has-prime-divisor? n)
(odd-primes-builder (+ n 2))
(stream-cons n (odd-primes-builder (+ n 2))))))
>=
5 generates the
>
n.
Exercises
Exercise 15.5:
stream of
ple, if
771
all
6,
m and increasing.
6, 7, 8, 9,
0,
list
first
15.3 Streams
is
the
For exam-
a stream of integers
A;) is
m)
1, 4, 9,
squares-of-integers whose
493
all- integers
Exercise 15.6:
Write the definition of all-integers (including both the positive and negative integers
and
increasing order.
then
2,
and then
0).
0,
then take
1,
then
-1,
-2, etc.
stream-f ilter-in
Exercise 15.7:
and a stream and returns a stream consisting of those elements of the original
stream for which the predicate is true. Test your program by filtering the
stream of positive integers using the predicate, which tests whether a number
is an odd multiple of 3. Use strezan->list to print the first 20 elements of
the resulting stream: (3 9 15 21
...
).
stream-ref
Exercise 15.8:
is
Then
use
for the
stream-member?
Exercise 15.9:
n elements
than
n, it tests
whether a
Exercise 15.10:
is
n,
strm
is
which
a
is
if
is
one of the
less
prime?
tests
on numbers such
Exercise 15.11:
The
finite
true
an element of strm.
is
a,
and 100000007.
positive-rationals
positive rational numbers, which are ratios of two positive integers a/6,
can be enumerated by
a.
listing
in lowest
Thus the enumeration begins with 1/1, 1/2, 2/1, 1/3, 3/1,...
Define a stream positive-rationals that contains all of the positive rational numbers with numerator and denominator having no common divisors
meration.
494
Using Streams
Table 15.28
greater than
(1 1)
(1 2)
(1 3)
(1 4)
(15)
(2 1)
(2 2)
(2 3)
(2 4)
(2 5)
...
(3 1)
(3 2)
(3 3)
(3 4)
(3 5)
...
(4 1)
(1 5)
(4 2)
(4 3)
...
(5 3)
(4 4)
(5 4)
(4 5)
(5 2)
(5 5)
...
sum
1.
...
diagonals
your program by
in lowest terms.
is
Test
stream-cdr
The procedure stream-cdr should have been implemented without the " >"
tag. Modify the definitions of stream-cdr and force so that when a promise
Exercise 15.12:
is fulfilled,
just
its
value
is
stored. (See
15.5.)
Compare this
version of the stream operators with those used earlier to evaluate the expression
diagonal
Exercise 15.13:
(i
up
(i
2)
(i
3)
1;
that
(2
is:
null-stream. Test
with 4 and
and returns a
finite
5.
Exercise 15.14:
i,
(1 i)
stream containing as
it
1)
=^
=>
((4 1)
(3 2)
(2 3)
(1 4))
((5 1)
(4 2)
(3 3)
(2 4)
(1 5))
stream-append
15.3 Streams
495
(stream-car finite-stream)
(lambda (i)
(stream- append (diagonal i)
is
evaluated.
Ex-
plain.
Exercise 15.15
can
Then complete
Data
In Section 15.5,
That
will
make
we look
at
an application of streams
known
cis
characters
to input
.
and output.
letters,
data type
is
handled
Since information
in
is
is
Using Streams
how
this
many computers
An example
of
used in
496
see
Scheme.
we
is
the
A 1.1
in
in
is
#\A. There
is
is
is
For example,
a Scheme pro-
its
In this
the
it.
ASCII code
For example:
^^
=
=
(chcur->integer #\A)
^
^^
^
(char->integer \b)
(cheir->integer #\0)
Scheme
65
66
97
98
48
49
>integer; that
is,
if
which
is
is
and
ASCII code
and we again
(integer->char 65)
Special
n,
=*
\A
Scheme characters
some of the
control characters
line feed) is
is
#\retum, which
and char>=?.
(char<? \C \F)
=>
We
ASCII
codes:
two
ch2a'=?, cliar<?,
have:
(char<? \B #\A) =* f
(char<? \A \a)
=>
Sometimes
it is
#t
and consider upperas the same. Then we would treat #\A and
letter
497
#\a
as
if
Two
true.
it
first
leaves
all
when
is
predicates
argument
argument
its
is
gument
as
a lowercase
when
its ar-
a letter:
(char-upcase #\a)
#\A
==*>
(char-downcase #\Z)
^^
(char-upper-case? #\A)
#\z
=^
#t
There are some string procedures that also make use of characters.
example, string->list
of characters that
is
make up
For
list
=>
To go
Exercises
Exercise 15.16:
We
string->list
become a
is
this set
make-string,
for
vector-ref there
for
vector-set
Exercise 15.17:
there
and returns a
is
string-set
list
and
for
(of characters).
list->string
498
is
vector-length
string-length. Using only string-rel and string-length from
of string-processing operations, write string->list, which takes a
string-ref
there
is
vector ihere
Using Streams
is
(define list->string
(lambda (list-of-characters)
(let
[1]
(define string-tester
(lambda (strng)
(let ((chars (string->list strng)))
(let ((s (list->string chars)))
(nesline)))))
[2]
(for-each string-tester
Exercise 15.18:
'
("abc"
"
string
like
Exercise 15.19:
"
all
must be
characters.
string-append
Define string-append, which takes two strings and returns a string (see Ex-
ercise 9.6).
lists.
append.
Exercise 15.20:
Icjer
Define a procedure lower that takes a string and returns a new string where
all
upperccise characters
Exercise 15.21:
become
lower!
it
so that all
flipflop
Define a procedure flipflop that takes a string and returns a new string
where all uppercase characters become lowercase and all lowercase characters
Exercise 15.22:
become uppercase.
499
hash-function
In Section 12.6, a naive-hash-f unction was used as a local procedure to
assign an integer to a string. It assigned the ASCII code of the first character in the string, modulo some fixed number (26 was used in naive-hashfiuiction). This method has the disadvantage that some letters are used
more frequently than others to start words, so the buckets would not be filled
Exercise 15.23:
uniformly.
codes of
all
is
modulo some
ASCII codes
of the
first
case sensitive,
that
it is
is
of the
m buckets.
Define
when passed a
modulo m
(that
sum
is,
of
the
case insensitive
its
ASCII
number m. This
fixed
will
the
sum
and
with the
it
so
if
15.5 Files
In this section,
from one
file,
we
reformats
it,
and writes
it
to another
file.
also
text
using
files in
that you write in the editor and to store the output of your
Scheme programs
file.
In
all cases,
directly
from a
file
It is
also
or write directly
an input port, and the material printed using a display or write expression
is
In general, a port
far,
is
known
as the standard
been associated with the computer's video display, known as the standard
output. These are the default values
500
Using Streams
if
no other port
is
or output.
It
make
also possible to
is
file
from
which we want to read items, or to make the output port be associated with
to which
file
file.
port returned
The
ment
is
file
file
"inputl.dat".
is
it
if
that argu-
file
((1 2)
to the variable
[1]
[2]
(read port-in)
port-in and
This
[3]
(read port-in)
is
[4]
(read port-in)
(3 4))
((1 2)
[6]
(read port-in)
When
message
has the
file is
performed on
it.
Since
finished,
when they
When
many computer
15.5 Files
same time,
it is
good practice to
close ports
and
tered
end-of-file
is
file is
is
encoun-
501
tests
example,
"input2.dat" contains
if
the
file
is
For
100
150
200
250
(letrec
((add- it ems
(lambda (sum)
(let ((item (read p)))
(cond
((eof -object? item)
(close-input-port p)
sum)
(add-items 0)))
sum
returns the
file
Scheme
provides the procedure read-cheur, which reads the next character. Scheme
writes that character using the #\-notation for characters. For example, the
character
is
written as #\A.
If
read-cheo:
is
argument must be a
Thus
if
file
Testing
port,
and
it
called with
If it
no argument,
"input3.dat" contains
12
(letrec
(eof-object? ch)
'()
(close-input-port p)
ans)))
502
Using Streams
it
returns the
list
(#\T #\e #\s #\t #\i #\n #\g #\space #\1 #\space #\2 #\space #\3)
To
file.
write directly to a
This
is
argument a
file,
we must
first
its
sent.
open- output -f il e
" output
dat
'
'
file
it
creates the
file
"output.dat".
file
"output.dat".
"output.dat".
If
the
If
the
file
file
does
does
exist,
using.
We
printed their argument on standard- output, which has been the computer's
argument.
When
a port
is
present as
its
its first
argument to that
is
port.
Similarly,
an example:
(close-output-port port-out))
sends the sentence
file
when one
is
finished.
This
its
ports,
is
it is
good practice
in the
file
For example, PC-Scheme and MacScheme delete the file and create a new one with the
same name, so that the previous contents of the file are destroyed. Some implementations
of Scheme may signal an error if one tries to open an output file that already exists.
'
15.5 Files
503
Program 15.29
file-copier
(define file-copier
(if
(begin
(write-char ch p-out)
(copier (read-chau: p-in)))))))
(close-input-port p-in)
(close-output-port p-out)))))
It is
file
its first
an output port as
present,
its
it
We
Program 15.29
stored in one
to another
file,
file.
reformats
We
it
some given
to have
we want
to convey.
We
It is
When f ile->stream
and made the
first
define
is
file
eflfort
to have
Program
first
character
to
describe
remove
it
all
to treat
handle
all
No
is
as a
file
15.30.
When
built.
stream is installed.
Our strategy is first
how
it
and prints
We
invoked, the
We shall
line length,
we
to the
after
it
not
is
file
sends
the ideas
it
identified
file
identified
If
is
closed
is
in this process
open, characters
of characters, for these are where the original line breaks were.
We
insert
504
Using Streams
Program 15.30
f ile->streain
(define f ile->streain
(lambda (filensune)
(let ((port-in (open- input -file
f ileneune)))
(letrec
(
(build- input-stream
(lambda
()
(begin
(close- input -port port-in)
the-null-stream)
(stream-cons ch (build-input-stresun) ))))))
(build-input-stream) ) ) )
last
word on one
from the
line
first
some cases, we may have put more than one space between words, so
we next eliminate all excess spaces; that is, whenever there are more spaces
than one between words, the extra ones are removed. Next we insert double
spaces at the end of each sentence. Finally, we count the characters and
line. In
desired
file.
is
name
of the input
The
file,
three arguments to
formatter
in
Program
15.31
We
first
applies these
formatter are a
name
string
of the output
file,
definitions of each of
The procedure that removes the newlines from the input stream is given in
Program 15.32.
If there is more than one space between words, the excess is removed by
the procedure remove-extra-spaces given in Program 15.33. This procedure
uses the helping procedure trim-spaces, which removes all spaces from the
is
it
in
Program 15.35
from a
we have
15.5 Files
is
is
used to guar-
in Pro-
505
Program
formatter
15.31
(define formatter
(remove-extra-spaces
(remove-newlines
(f ile->stream
Program 15.32
input-file))))))))
remove-newlines
(define remove-newlines
(leunbda (str)
(stream-map
(lambda (ch)
(case ch
str)))
Program
remove-extra-spaces
15.33
(define remove-eztra-spaces
(lambda (str)
(cond
(stream-cons #\space
(remove-extra-spaces
(trim-spaces (stream-cdr str)))))
(else (stream-cons
(stream-car str)
506
Using Streams
Program 15.34
trim-spaces
(define trim-spaces
(lambda (str)
(cond
Program 15.35
insert-double-spaces
(lambda (str)
(cond
((streeun-null? str) str)
(stream-cons
stream-car str)
(stream-cons #\space
(stream-cons #\space
(
insert double-spaces
(trim- spaces (strejun- cdr str)))))))
Program
15.36
end- of -sentence?
(define end-of-sentence?
(leunbda (ch)
gram
15.34, to
(char=? ch \
know
(char=? ch #\?))))
left.
it is
better to
make
is
exactly
the procedure
do what
its
its
specification dictates
argument
15.5 Files
is
507
Program
insert-newlines
15.37
(if
str
(let ((n (coiint-chars-to-nert-space str)))
(if
(addl count)))
(stream-cons SXnewline
(insert (trim-spaces str) 0))))))))
(insert
Program
15.38
(define count-chars-to-next-space
(lambda (strm)
(letrec
(
(count-ahead
(lambda (str count)
(cond
(count-ahead
The
stm
(addl count)))))))
0))))
file
is
The procedure insert-newlines given in ProWhenever a newline is inserted, we must remove any
gram
is
how many
line or
of the
characters
whether
number
it
it
contains in order to
should be the
first
508
Using Streams
count-chars-to-next-space, defined
know whether
word
in
is
it fits
line.
know
on the same
This counting
Program
15.38.
Program
15.39
streain->f ile
(filename stream)
(letrec
(write-stream
(lambda (str)
(not (stream-null? str))
(if
(begin
(write-stream stream)
(close-output-port port-out)))))
When
lists
processing small
files, it
by the procedure
file
However,
the output
it
if
the
file is
stream-car
in
stream->f ile
is
is
completed over
demand
That demand
is
for
prop-
spaces, remove-newlines
all
the
is
file
files
and
and
this
program
is
15.5 Files
It
makes an
509
Exercises
Exercise 15.24
A file contains
first
file
line.
file
sum
file is
first
file
Exercise 15.25
columns: the
first
file
one per
line.
column of both
files
files
and the second contains the running sum and running product,
of the integers in the
is
first
file
respectively,
file
Exercise 15.26
Write a program that
will
file
containing text.
in order
and you
will discover
Exercise 15.27
Test formatter developed in this section.
Exercise 15.28
Test the procedure formatter defined below.
In order to do this,
(define fomatter
((insert-newlines line-length)
(insert-double-spaces
(remove-extra-spaces
(renove-newlines
(file->8tream input-file))))))))
510
Using Streams
you
will
Exercise 15.29
Test the procedure formatter defined below.
first
to that result.
(define formatter
(leunbda (output-file line-length)
(lambda (input -file)
( (stream->f ile output-file)
(( insert -newlines line-length)
(insert -double-spaces
(remove-extra-spaces
(remove-newlines
(file->stream input-file)))))))))
Exercise 15.30:
apply-procedures, compose
(lambda (procedures)
(if
(null? procedvires)
(lambda (x) x)
(compose
(car procedures)
it
define
compose
to take
is
the
same
as
((apply-
previous exercise.
(define formatter
(lambda (output-file line-length)
(compose
(stream->f ile output-file)
( insert -newlines line-length)
insert-double-spaces
remove-extra-spaces
remove-newlines
f ile->stream) )
15.5 Files
511
Exercise 15.32
(compose
(streaiii->f ile
output-file)
f ile->streain)
b.
(compose
(stream->f ile output-file)
remove-newlines
f ile->stre2uii)
512
C.
(compose
(stream->f ile output-file)
remove-extra-spaces
remove-newlines
f ile->stream)
d.
(compose
(stream->f ile output-file)
(insert-newlines line-length)
remove-ertra-spaces
remove-newlines
f ile->stream)
e.
(compose
(stream->f ile output-file)
(insert-newlines line-length)
remove-newlines
f ile->stream)
Using Streams
Part 5
Control
When we
to Part
we can begin
1,
is
When
control.
The
off dessert.
is
Imag-
a photo of
cafe in Paris
can
Do you
one of us polishing
is
power of abstracting
here
to understand the
photograph.
long ago.
When
We
will
We may
that happens,
we escape
to the
same
where we were
cafe
be the same,
we are heavier,
then we are the same.
or not, or whether
may
little
one way we
have the same waiter and perhaps order the same food.
is
like
If not,
will
depend on
If so,
then some
may
have changed.
Perhaps the genie rubbed the wrong photograph, and instead of rubbing the
cafe,
What a shame, thrust back to that delicious cafe and not reliving the
What happens after the meal is over? You have two choices. You can
waiter.
meal.
stay in Paris
life,
as
is
computer
is like
it
you are
in the
around,
it
computation.
tell it
The pho-
514
is
to
Control
Introduction to Continuations
16
16.1
Overview
Did you ever
lie in
bed early
in the
my
my teeth,
After
first class.
get to
concept, relative to
some point
my first
class,
You packaged
in the
I'll
my way
"I've
like this:
to
campus, and
have
out what you would do with the rest of the day; you formed an abstraction
of the rest of the day.
In
Scheme
in the
chapter
well.
in
Scheme.
It
shows
what they are, how they work, and when to use them.
When we learn to deal with continuations, we shall be able to do all sorts
of interesting things. For example, we shall be able to exit with a result from
within a deep recursion. In addition, we shall be able to design break packages
in this
must be acquired.
The
first
new concepts
contexts
and
es-
The second
to the point
of
its
invocation.
escape procedure.
continuation
is
made
into an
with-current-continuation.
its
dividend divisor))
(/
'(a b c))
The
when
that that
describe
is
element
is
is
either an invocation of
a number.
If
error or a
list
procedure, then
length four,
first
how
it
returned,
now
we observe that if error gets invoked, no consing occurs. In the next section
we develop contexts, procedures that describe what does not happen when
such escape procedures get invoked.
16.2 Contexts
context
is
We use
If e is
a subexpression
The
(* 4
(+ 5 6)))
expression
is
First,
add 5 and 6
and get 11. Next multiply 11 by 4, yielding 44, and then increase that result
by 3. Now, what is the context of (+ 5 6) in that expression? We must find
a procedure that,
if
passed the value 11, will produce 47. There are lots of
such procedures, but we will find one by using a simple two-step technique.
In the
first
we
step
replace
e,
that
is,
(lambda (D)
(+ 3
516
(* 4
).
The context
(+ 5 6)))
Introduction to Continuations
of (+ 5 6) in
we
wrapped within
is
is
the value
of:
(lambda (D)
D)))
(+ 3 (* 4
Then applying
What
is
the context of (* 3 4) in
(+ (* 3 4) 5) 2)
To form
this context,
we simply
replace
3 4) by
is
the value
of:
(lambda (D)
(*
Applying
34.
(+
5)
2))
does applying
it
it
to other values.
(+ 12 5)
Applying
which evaluates to
2),
it
to 3 yields 16.
to 24 yield?
step
What
first
Before,
The second
all
we did
step
in the
(if
(zero? 5)
(+ 3
(* 4
(+ 5 6)))
(+ (* 3 4) 5) 2))
first
step
is
what
is left
after evaluating
(if (zero? 5)
(+ 3
(*
(+
16.2 Contexts
4 (+ 5 6)))
5)
2))
517
(zero? 5)
leads to
is false,
(+
so
is
the value of
(lambda (D)
(*
(+
5) 2))
in:
D)
(if (zero? n)
(writeln (+ 3 (* 4 (+ 5 6))))
(writeln (* (+ (* 3 4) 5) 2)))
n)
The
is:
(begin
(writeln
(+
5) 2))
n)
The begin
is
needed because
it is
we cannot do the
a sequence of expressions.
We
We
cannot do
addition,
do the multiplication,
it.
The
remem-
value of expressions, we work from the inside and try to work outward.
is
responsible for
We
are
and we do not need to worry about the if expression. Evaluation proceeds until the presence of D makes it impossible to continue and
the
let
expression,
is
the value
of:
(lambda (D)
(begin
(writeln (* (+
5) 2))
n))
Applying
bound
it
to 6 leads to (begin
displayed.
518
Introduction to Continuations
is
The
last
let
expression
is
We
(define tester
(lambda (n)
(if
(zero? n)
(writeln (+ 3 (* 4 (+
(writeln (* (+
5 6) ))
3 4)
5)
2)))
n))
be formed.
10 (tester
If
we were looking
D), then
1), we know
same context
of:
(lambda (D)
10
(begin
(writeln (* (+
2))
5)
n)))
(begin
(writeln 0)
(let ((n
(if
D)
(zero? n)
(writeln (+ 3 (* 4 (+ 5 6))))
(writeln
(+ (* 3 4) 5) 2)))
n))
We
are
still
replaced by
At the
first
step,
(* 3 4)
is
(begin
(writeln 0)
(let ((n
(if
D)
(zero? n)
(writeln (+ 3 (* 4 (+
(writeln (* (+
5)
6))))
2)))
n))
16.2 Contexts
519
First,
which
is
Then
displayed.
is
the value
the context
is
of:
(lambda (D)
(begin
(writeln
(*
(+
2))
5)
n))
Invoking
it
The context
1.
let
expression
is
is
similar to
an assignment
of (* 3 4) in
(begin
(writeln 0)
(let ((n
D)
(zero? n)
(if
(writeln (+
(* 4
(writeln (* (+ (*
(set
(+ 5 6)
3 4)
) )
2)))
5)
n (+ n 2))
n))
is
the value of
(lambda (D)
(begin
(writeln (* (+
(set
5)
2))
n (+ n 2))
n))
The
the context
integer,
is
and what
From
the
way
in
we look
Each time
is
also increased.
If
<c>
is
this
may
520
expression.
procedure invocation.
let
list, it
is
cation assigns 5 to n.
it
of <c>,
is
list,
Introduction to Continuations
(define map-addl
(lambda (Is)
(if
(null? Is)
(cons
(+3
(* 4 5))
'())
'
(1 3 5))
is
(2 4 6 23).
What
is
the context
this until
context."
We
of (* 4 5) in (cons
for
D:
(cons
(cons
^^
=>
(cons
(cons
(cons
(cons
^^
^^
Q) '())))))
is
(lambda (D)
(cons
(cons 2 (cons 4 (cons 6 (cons (+ 3 D)
we invoke
If
invoke
it
on
this context
13,
we
get
it
5,
(0246
on
we
create the
16).
show up
'()))))))
(02468),
list
What makes
this a bit
is
and
unusual
if
is
we
the
considered.
we know that D
will occur, so
(define siim+n
(lambda (n)
(if
(zero? n)
(+ (addl n)
What
As
is
in the previous
16.S Contexts
when n
is 3,
in (*
10 (sum+n 5))?
521
differs
Stepping through
(* 10
(sum+n 5))
(* 10
(if
(zero? 5)
(+ (addl 5)
(+ 6
(* 10
(+ 6 (if (zero? 4)
(*
(+ (addl 4)
(+ 6
(+ 5
(sum+n 3))))
10 (+ 6
(+ 5
(if
(+ 5
(+
(* 10
(+ 6
is
(subl 5)))))
=^
=>
=>
(zero 3)
(siiin+n
^*
(sum+n 4)))
(* 10
(* 10
However, this
(+
=*
(sum+n 2)))))
(lambda (D)
(* 10
The
(+ 6
(+ 5
(+
(sum+n 2))))))
final
if
expression.
First,
D)
is
Consider the
determining the
8 9). There
no
is
the value of
(lambda (D)
(zero? D) 8 9)).
(if
When
gets
this context
bound
is
applied,
its
value will be 8 or
9,
to D.
The
exercises
Exercises
Exercise 16.1
What
What
is
results
when we apply
'())in(cons
this context to
'
(3)?
^
The trace that follows assumes a left to right order of evaluation of the operands to +.
The procedure map-addl imposed a left to right order of evaluation of the operands to cons
by using a
522
let
expression.
Introduction to Continuations
Exercise 16.2
For the following exercises assume these bindings: a
is 5,
is 6,
and z
is 7,
is 8.
Each answer
will
is 4,
first
is 1,
is 2,
is 3,
part, describe the context of each expression; in the second part, determine
and
5,
7.
(+ a b)).
a.
(+ a b) in
b.
x in (+ X y).
c.
y in (- X y).
d.
e.
(* c
f.
(zero? n)
g.
X in (if X y z).
h.
(+ a x)).
(+ a b)) in (+ d (* c
in (if
(+ a b))).
(zero? n) a b).
Exercise 16.3
For each expression below, determine the context of (cons 3
result of applying that context to (1
a.
'
2 3).
(f 3))
b.
We now
introduce a
new procedure
An
escape
procedure upon invocation yields a value but never passes that value to others.
When an
escape procedure
computation.
is
invoked,
its result
result
is
is
is
ignored.
an escape multiply:
523
(+ (escape-* 5 2)
3)
is
abandoned.
It is
as
if
(* 5
At
this point
is
procedure.
define
escape-*
and
((escaper *)
(+
5 2)
3)
evaluates to 10.
(lambda (x)
(-
(* I 3)
7)))
5)
4)
this
is
the
same
as
((lambda (x)
(-
(* X 3)
7))
5)
so the answer
is 8.
tion procedure:
(+ ((escaper
(lambda (x)
((escaper -) (* x 3) 7)))
5)
4)
This
is
and +
abandoned.
is
is
determined,
multiplication procedure:
524
(escaper -)
Introduction to Continuations
(+ ((escaper
(lambda (x)
((escaper -) ((escaper *) x 3)
7)))
5)
4)
The invocation
same
1.
((lambda (x)
value.
The
The (escaper
-)
is
never
Why?
(* X 3))
5)
2.
(+ ((escaper
(lambda (x)
(- ((escaper *) x 3)
7)))
5)
4)
3.
(+ ((lambda (x)
((escaper -) ((escaper *) x 3)
7))
5)
17)
4.
(+ ((lambda (x)
((esraper
(-
x 3)
7))
5)
2000)
Does
Not
quite.
(/
(+ ((escaper
(lambda (x)
(-
X 3) 7)))
5)
4)
2)
The awaiting
tion, also
addition
is
abandoned.
Is
the addition
hcis
since
525
also
been abandoned.
if e is
e.
The
is
the
same
(e
is
its
the context of the escape invocation included the awaiting addition and the
awaiting division.
We
Exercises
Exercise 16.
Evaluate each of the following:
a.
b. (let
Exercise 16.5
Using the definition of es-cons from the previous exercise, determine the context of
(es-cons 3 '())
Exercise 16.6:
in
(es-cons
reset
(escaper
(lambda
()
(reset)).
Exercise 16.7
Let
is
let
arbitrary
this
be generalized to an
Exercise 16.8
Let / be any procedure.
When
526
Introduction to Continuations
still
16.4 Continuations
We
call/cc
is
Program
call-with-current-continuation
it
(or call/cc). If
as follows:
call/cc
16.1
call/cc
The
is
receiver
call
Its
argument
is
called a con-
4 (call/cc r)))
The context
of (call/cc r)
(lambda (D) (+ 3
is
it
is,
after the
the value of
D)))
(+ 3 (* 4 (r (escaper (lambda
That
is
(D)
cis:
(+ 3
D)))))))
is
now
little
is
helpful.
What
is
Let us
the value
(+ 3 (* 4 ((lambda (continuation) 6)
16. 4 Continuations
4 D)))))))
527
The
value of
((lambda (continuation) 6)
(escaper (lambda (D) (+ 3
is 6; it
about
(+ 3
4 D)))))
(* 4
((lEunbda (continuation)
The
explicit invocation of
27
(i.e.,
4*6).
What
result
is
(continuation 6))
(+ 3
(+3
(* 4
D))))
D) ))))))
(continuation 6)))
(+ 2
3
(* 4
continuation on
(+3
(* 4
6)
any different?
explicit invocation of
(* 4
continuation on 6 leads to
(+ 3 (* 4 ((lambda (continuation)
The
is
one?
D))))
D)))))))
6 leads to
6)
and then the result is 27. Remember, an escape invocation abandons its
context, so (lambda (D) (+3 (*4 (+2 n))))is abandoned, continuation has the value (escaper (lambda (D) ... D ...)). Because the
context of a call/cc invocation
is
r.
528
Introduction to Continuations
Exercises
Exercise 16.9
For each expression below, there are four parts.
this expression.
original
c,
define
The
is
given below:
(- 3
[1]
(* 5
a.
-22
b.
(let
(* 5
D) ))))))
(r (lambda (continuation)
(- 3
c.
(- 3
(* 5
(continuation 5))))
(call/cc r))))
(define r
(lambda (continuation)
(continuation 5)))
d.
(- 3
(* 6
(call/cc r)))
[2]
(-3
(* 5
((lambda (continuation) 5)
(escaper (lambda (D) (- 3 (* 5 D)))))))
[3]
(-3
(* 5
Exercise 16.10
If
is
in
(.
(call/cc r)
),
why can r be
botij/))
rewritten as
16. 4
5S9
Exercise 16.11
Ifr
is
in
(.
(call/cc r)
),
when can r be
rewritten as
16.5
Experimenting with
We next
call/cc
of a receiver
(remember that a
receiver
is
without using call/cc and one that uses call/cc. The point of these experi-
ments
is
to
Although the
differences
characteristics of
in the first
call/cc expressions.
two experiments,
their
Program
16.2
in
Program
16.2.
(define receiver-1
(lambda (proc)
(proc (list 1))))
(define receiver-2
(lambda (proc)
(proc (list (proc (list 2))))))
(define receiver-3
(lambda (proc)
(proc (list (proc (list 3 proc))))))
Each
receiver
but
it is
an argument.
is
is in-
We
each of these receivers using two global variables, result and resultcc, given
530
Introduction to Continuations
Program
16.3
result, resultcc
Program
16.4
(define writeln/retum
(lambda (x)
(writeln x)
x))
(define einswer-maker
(Icuubda (x)
(define call
(Izunbda (receiver)
(receiver writeln/return)))
Program 16.3, and three simple procedures, writeln/return, answermeJicer, and call, given in Program 16.4. The procedure writeln/return
displays and returns its argument.
The procedure answer-maker is like
writeln/return, but instead of returning its argument, it returns the consing
of aoiswer-is to its argument. Thus, (receiver-1 answer-meiker) displays
(1) and returns (eoiswer-is 1). The procedure call invokes its argument
on writeln/return.
in
For reasons that are not yet clear but will be by the end of this section, we
use set! to hold the results of each experiment.
Recall that
receiver-1
is
the value of
(leunbda (proc)
531
Experiment
1:
A.
[1]
(1)
(1)
[2]
result
(ansHer-is
1)
B.
[3]
(1)
[4]
resultcc
(answer-is
These
in
1)
call so there
the value
is
A writeln/return is invoked
in Part
is
of:
(escaper
(lambda (D)
(set! resultcc (answer-meiker D))))
Then
this continuation
cedure, that
(list
is
that happens.
is all
At
[4]
For Experiment
we
and
verify that
2, recall
its result,
resultcc
that receiver-2
is
is
(eoiswer-is 1),
the value
2:
A.
[1]
(2)
((2))
((2))
[2]
result
(answer-is (2))
532
Introduction to Continuations
is
invoked on
is
assigned
(lambda (proc)
Experiment
an escape pro-
to resultcc.
it is
of:
B.
(set! resultcc (answer-maker (call/cc receiver-2)))
[3]
(2)
[4]
resultcc
(answer-is 2)
In Part
which
is
the
main
difference
is
a writeln/return. The
returns, its
argument
is
first
time
is
with (2) as
its
writeln/return.
It
When this
Now we are ready
argument.
(2)
).
argument ((2))
argument by invoking
displays
and returns
its
set of
why
is
it
abandons
the value
and
is
its
is
an escape procedure.
Thus,
(lambda (D)
(set! resultcc (answer-maker (proc (list D)))))
The list invocation and the proc invocation waiting for the result of list are
abandoned. The list invocation not occurring accounts for the missing set
of parentheses, and the proc invocation not occurring accounts for why only
one (2) is displayed. In Part B when proc, the continuation, is invoked, its
argument is passed to the waiting answer-msJcer. The value (2) is displayed,
and the result (answer-is 2) is sent to the waiting set!. The set! causes
the value (answer-is 2) to be associated with resultcc. The result of the
experiment
We
is
earlier ones.
B.
We
verified at [4]
recall
last
is
this,
slightly trickier
before
than the
we look
at Part
(lambda (proc)
(proc (list (proc (list 3 proc)))))
Experiment
3:^
is
533
[1]
(3 <wriieln/return>)
((3 <writeln/retuTn>))
((3 <writeln/return>))
[2]
result
(answer-is (3 <writeln/return>))
[3]
(1000)
(1000)
[4]
result
(answer-is (3 <wriieln/return>))
The
result of
is
(.<writeln/return>
(list i<writln/return>
(list 3 <writeln/return>))))
First, the list (3
<writeln/return>)
argument. Then a
and that
result,
is
passed to <writeln/return>.
is
At
priate assignment.
<wrvteln/return>
is
duti-
set of parentheses
((3 <writeln/return>))
It
is
list
is verified.
At
the appro-
As expected <writeln/return> displays its argument (1000) and returns (1000). At [4] nothing has changed result.
is
Although
this
is
do simple things.
We
are
now ready
to consider Part B.
B.
[5]
<ep
(3
[6]
resultcc
(answer-is 3 <ep>)
[7]
(1000)
[8]
resultcc
(answer-is 1000)
The
534
result of
Introduction to Continuations
is
(<ep>
(list (<ep>
(list 3 <ep>))))
where <ep>
is
the value of
is
(escaper
(lambda (D)
(set! resultcc (answer-maker
D))))
is
receiver-3)
is
is
is
answer-is
is
Then
list
(list 3 <ep>)).
(3 <ep>).
Next
<ep>).
,
its
we
the set!
verify that
result of
The procedure aLnswer-maker displays its ar(answer-is 1000). The list (answer-is 1000) is
it
it
was invoked.
Exercises
Exercise 16.12
Rewrite aoiswer-maier using call.
Exercise 16.13
Run
(define exer-receiver
(lambda (proc)
(list (proc (list 'exer proc)))))
535
Exercise 16.1
For each expression below, describe the binding that continuation gets, and
give the value(s) of the expression. Each expression
once.
a.
We
must be
tested
more than
(continuation 6))))
(
The
(+ (call/cc r) 3) 8))
b. (let
(D)
(* (+
3) 8))), 72.
(
c.
(+ (call/cc r) 3) 8))
(+ (call/cc r) 3) 8))
d. (let
(
e.
(continuation 6)))))
(+ (call/cc r) 3) 8))
(continuation 6)))))
(+ (* (+ (call/cc r) 3) 8)
(*
f.
(+ (call/cc r) 3) 8)))
(continuation
(if (zero? (continuation (random 2)))
(+ 1000 6)
6)))))
(+ (* (+ (call/cc r) 3) 8)
(* (+ (call/cc r) 3) 8)))
Exercise 16.15
Determine the outcome of Experiment 3 with [1] and [5] replaced by the
expressions below.
[1]
(begin
(set! result (cuiswer-meJcer (call receiver-3)))
'done)
536
Introduction to Continuations
[5]
(begin
(set! resultcc (answer-maker (call/cc receiver-3) ))
'done)
Exercise 16.16
We
define a procedure
list
it
list
list
of
deep to a continuation.
(define map-subl
(leunbda (Is)
(if
(null? Is)
(let ((receiver (lambda (k)
(set! deep k)
'())))
(call/cc receiver))
(cons (subl
(ccir
Is))
(1000)
[2]
[3]
(1000 -1)
[4]
7
[5]
(1000
[6]
-1)
7
[7]
(1000 4 3 2
[8]
'(543210)))
10-1)
formed
at [1]
is
reset.
The
first
continuation
is:
537
(escaper
(lambda (D)
(cons 1000 D)))
At
[3]
is:
(escaper
(lambda (Q)
(cons 1000 (cons -1 D))))
The
third continuation
formed at [6]
is:
(escaper
(lambda (Q)
(cons -1 D)))))
is
and then
fill
the experiment.
We now
have
Program
all
the tools
we need
to define escaper:
escaper
16.5
(lambda (x)
(escape/thunk* (lambda
Although escape/thunk*
the right value.
To remedy
this experiment,
538
a receiver
is
Introduction to Continuations
(proc x))))))
this,
is
()
it
Program
receiver-4
16.6
(define receiver-4
(Icunbda (continuation)
(*escape/thimk* (launbda
We
()
then have:
[1]
((call/cc receiver-4))
escaper is defined
[2]
(*escape/thunk* (lambda
(addl 6)))
7
[3]
(+ 5
(escape/thunk* (lambda
()
(addl 6))))
At
system.
It
it.
its
in
Program
16.5.
Next escape/thunk*
is
()
to
(launbda
Finally,
(dcimbda
displays
()
escaper is defined. At
[2]
(lambda
yields 7; at [3]
invoking
it
7.
escape/thunk* on
invoking
(addl 6))
on
(lambda
()
(addl 6))
Because *escape/thunk*
is
context
539
is
abandoned.
Earlier
we hypothesized escaper's
is in
is
it
were.
On some
systems,
it
may
Now we
have
but
it
behaves as though
it
accepts proce-
Program
16.7
escaper
(define escaper
(lambda (proc)
(lambda args
(escape/thunk*
(lambda
()
and
exercises of
this chapter.
Exercises
Exercise 16.17
Assume
caper.
use call/cc.
Exercise 16.18
Exercise 16.19:
()
0))).
reset
7,
when we
defined error,
For example,
[1]
(cons
(reset))
reset invoked
540
Introduction to Continuations
we assumed the
existence of reset.
Exercise 16.20
Explain
causes an error.
Exercise 16.21
(let
(r
(escaper
(lambda (proc)
(cons 'c (proc (cons 'd '())))))))
[2]
(let
(r (escaper
(lambda (proc)
(cons 'c (cons 'd '()))))))
(cons 'a (cons 'b (call/cc r))))
Exercise 16.22
Consider the procedure new-escaper below.
(define new-escaper "smy procediire")
(let ((receiver (lambda (continuation)
(set
new-escaper
(lambda (proc)
(lambda args
(continuation
(lambda
()
(lambda
()
Why
is
new-escaper
better
than
escaper?
specific,
like to
separate
(= r tsLTget)
5^1
Program
how-many-till
16.8
(define hos-many-till
(lambda (n teirget)
(let ((count 0))
(cycle-proc
(lambda
()
(= r target)
What
is
example
is
that
it is
first
value of
542
is
Introduction to Continuations
is
the
Program
16.9
how-meuiy-till
(define hos-many-till
(lambda (exit-above-threshold)
(let ((count 0)
(svim 0))
(cycle-proc
(lambda
()
(begin
(writeln "target
"
"
tsirget
required
"
count
"
trials")
(set
(if
(>
count 0)
sum thresh)
(exit-above-threshold sum)))
(set! count (+ count 1)))))))))
(call/cc receiver))))
Program 16.10
random- data
(define random-data
(lambda (n thresh)
(letrec ((loop (leunbda (target;
(cond
(escaper
(lambda (Q)
(cons D (loop (subl target)))))
where loop
is
as
it is
defined in
is 9.
543
Exercise
Exercise 16.23
Explain
why
get).
all
We
the
number n
to the product
(product+
'(3 6 2 7))
(product*
'(2 3
Here
is
A simple exam-
8))
if
the result
=>
=^
is
(+ 5 252)
nonzero:
=>
257
product
Prograini 16.11
(define product+
(lanbda (n nums)
(letrec
((null? nuMs)
1)
(else
[*
icdir
(zero? prod)
(+ n
prod))))))
list is
This version
Finding
544
is
in
test to
determine
if
one of the
Program
16.12.
first
fact:
computation of product. In
fact,
what happens
k
zero.
zero
is
in the
is
is
that
if
the
Introduction to Continuations
first
Program 16.12
product
(define product*
(lambda (n nvuns)
(letrec
((null? nums)
1)
invocations includes k
the k
(+ n prod))))))
multiplications.
Is it possible to exit
the zero
is
found, each of
be done.
solution
numbers contains a
still
When
is
(2 3 4
in
Program
16.13. Consider
6 7))).
Since the
list
of
is
'
is
the value of
(escaper
(lambda (D)
(+ 100
D)))
is
being invoked on
0.
If,
is
100.
however, no zero
is
is
is
(+ n prod).
Program
We
The
is
in
16.14.
list
uation formed from the invocation of (call/cc receiver) and finishes the
if there is a
where in the
list
zero in the
list,
fact
545
Progrson 16.13
product*
(define product*
(lanbda (n nuns)
(let ((receiver
(lambda (exit-on-zero)
(letrec
((null? nums)
((zero?
(ceir
1)
(+ n prod)))))))
(call/cc receiver))))
Program 16.14
product*
(define product*
(lambda (n nums)
(let ((receiver
(null? niims) 1)
(else
(4
(car nums)
(call/cc receiver))))
16.9 Escaping
product*
of numbers.
(product*
546
Specifically,
'((1 2)
(1
Introduction to Continuations
(3
D)
(((((1
0)
1)
4)
1)
1)))
is
to
lists
Program 16.15
product+
(define product*
(lanbda (n nims)
(let ((receiver
(labda (exit-on-zero)
(letrec
((product
(leunbda (nuns)
(cond
((null? nuBs) 1)
(cen:
nuns)
(call/cc receiver))))
Program 16.16
-emd-count-maJcer
(define *-and-count-m2Jcer
(lambda
(let ((local-counter 0))
local-counter)
"
(* nl n2)))))
which results
in 0.
However,
if
the
had been a
all,
is
3,
we can
discover
given in
Program
By counting
16.15.
the
number of
Program
16.16,
to product+.
again introduced
we can
all
in a functional style
in
an argument
Program
16.17.)
Thus
invoke:
547
Program
16.17
prod.uct+
(define product+
(leunbda (n nums *-proc)
(letrec
(
(product
(lambda (nums)
(cond
((null? nums)
1)
nums)
(ceu:
(else
(let ((val (product (car nums))))
(cond
((zero? val) 0)
(else (*-proc val (product (cdr nums)))))))))))
(let ((prod (product nums)))
(+ n prod))))))
(num-list '((1 2)
(product+
(1
(3
1))
(((((1
0)
1)
4)
1)
1))))
5 niim-list coiinter))
When product+
multiplications,
it
of course, a
two
is,
pcisses
through the
list
way
(it
would require
list).
Exercises
Exercise 16.24
Run product +
numbers
0.
to
Run product +
list
548
of
of
if
the
list
list
of
contains a
first
Introduction to Continuations
Exercise 16.25
Run product+
Exercise 16.26
Rewrite product + of Program 16.15 where n
is
always
0.
Exercise 16.27
Rewrite product+ of Programs 16.14 and 16.15 using a local variable to maintain the accumulating product.
Can
this
549
Using Continuations
17
17.1
Overview
we discover some unusual properties
In this chapter
and then
restart
an
how
indefinite
facility.
number
be able to interact
of continuations.
process. Before
we begin
this
We
concerning call/cc.
17.2
Review of
call/cc
1.
call/cc's argument
2.
receiver's
is
argument
called a receiver.
is
called a continuation.
It is
an escape procedure
<ep> of one argument formed from the context of the call/cc invocation.
S.jA continuation's argument
is
is
is
then ignored, the following hold, where the use of ellipses surrounding an
expression indicates that the expression
may
be embedded:
(call/cc receiver)
(receiver 'anything)
...
body
...)
and
(call/cc receiver)
=
=
(receiver 'anything)
(receiver 'anything)
body
and the
dure,
5.
...)
last equality
continuation
is
is
an escape proce-
ignored.
(call/cc receiver)
and
(let ((receiver (escaper (lambda (continuation) (continuation 6o(ij^)))))
.
(call/cc receiver)
552
(call/cc receiver)
Using Continuations
Program
countdown
17.1
(define countdown
(launbda (n)
The non-negative-number:
"
"
v)
(positive? v)
(writeln "Blastoff"))))))
17.3
we introduced continuations. We noted that continuaand could be the value returned by any procedure
or could be stored in data structures; however, our examples (except for the
third experiment
feature.
property that once a receiver was exited, the continuation was useless. Each
receiver's continuation
it
names
as
exit-above-threshold and
Now we abandon
its
we used a continuation to exit deep recursions with the various definitions of product +. However, we have not yet developed an interesting use of
a continuation, other than escape/thunk*, that can be returned as a value
and stored in a data structure. To illustrate such a continuation, we define a
procedure countdown that counts a positive integer down until it reaches zero.
Earlier
This
is
We
first
perform a loop. The second does create a single continuation and with this
continuation
is
trivial displaying
The
definition of
countdown uses a
Programs
17.1, 17.2,
The
is
The
and
17.3.
One Continuation
as <proc>. Here
553
Progrun 17.2
message
(define message
(writeln
"
"
"
value)
value))
Program
attempt
17.3
(define attempt
(lambda (n)
(let ((receiver (lambda (proc) (list n proc ))))
<proc
second argument,
(attempt
list
3.
(list n proc)
This produces
its
3).
an attempt
is
is
list
constructed, attempt
is
Next we attempt to
the message
is
<proc>).^^
The
invocation's value
is
(3 <proc>).
and bind
returner to <proc>. We display a message that acknowledges where we are
and that we do indeed have the correct value. The message is, "The non-
negative number:
3."
We
list,
if
the
number
is
3,
positive.
In
it is.
We invoke
We now
that
554
redefine
we return
attempt
(see
Program
Using Continuations
<ep>
we explain
Program
attempt
17.4
(define attempt
(lambda (n)
(let ((receiver (lambda (proc) (list n proc))))
(call/cc receiver))))
(1 <ep>)
(0 <ep>)
Blastoff
(message "Enter"
3" and
second argument,
3.
is
constructed, attempt
list .(3
is
is
This produces
message returns
it is
exited.
message
an attempt
its
3).
is
list
(3 <ep>)).
We
if
the
number
is
positive.
and hand
We
We
In this case
it
form the
(2 <ep>)
list
is.
To this point, everything has been the same as in the analysis of attempt
of Program 17.3. In fact, all we did to write the above paragraph was change
instances of <proc> to <ep>. Now we are doing something new. Instead of
invoking <proc>, we are invoking <ep>. The continuation <ep> is the value of
One Continuation
555
(escaper
.aabds
(returner
"
(sriteln
(if
(2iid
pair)))
The non-negative-number
"
v)
(positive? v)
This continuation
That
attempt.
formed as the
is
is,
is
(2 <ej>>)."
<ep>).
We
let
The
To go a
list,
message invocation
is
(2
binding ret^imer to the same <ep>. Once again we display a message that
acknowledges where we are and that we do indeed have the correct value.
to see if
Exercise
Exercise 17.1:
cycle-proc
Program
556
14.11.
Using Conttnuattoru
In this section
we
continuation,
frees us
we
In this experiment
formed
Program
in this
17.5
we need a
it
receiver
receives as
This
and a
testing procedure.
The
receiver
one example, so
it is
receiver
(define receiver
(lambda (continuation)
(continuation continuation)))
Program
17.6
tester
(define test(ar
(lambda (continuation)
(writeln "beginning")
(call/cc continuation)
(writeln "middle")
(call/cc continuation)
(writeln "end")))
Experiment:
[1]
beginning
beginning
middle
beginning
end
[2]
The
first
event
is
to
if it
557
is
the value
of:
(escaper
(lambda (D)
(tester D)))
We
We
Now continuation
is
bound
to <ep>.
We
write beginning.
We
next invoke
thing about what <ep> does with <epa>, we must understand what <epa>
does
if it
is
the value
of:
(escaper
(laabda (D)
D
(writeln "iddle")
(call/cc <cp>)
(writeln "end")))
ignores
its
its
it
displays end.
its
Now
in-
recall
argument,
does
if it
is
the value
of:
(escaper
(laabda (D)
D
(writeln "Middle")
(call/cc <epa>)
(writeln "end")))
The
its
(call/cc <epa>), and when that returns, it displays end. Now recall that
<epa> takes its argument (ignores it) and displays middle, which we do now,
and then invokes (call/cc <ep>). Once agaun we form the new continuation
<epc>, which
is
the value
(escaper
(lambda (D)
D
(writeln "end")))
558
Using Continuations
of:
which
is
the value
its
of:
(escaper
(lambda (D)
D
(writeln "middle")
(call/cc <epc>)
(writeln "end")))
This continuation displays middle, invokes (call/cc <epc>), and when that
returns,
it
displays end.
What
is
all
is
it,
Exercises
Exercise 17.2
many more
invoked?
Exercise 17.3
Determine what
(call/cc continuation))))
(call/cc receiver))
What
17.5 Escaping
is
(call/cc call/cc)?
559
Program
17.7
f latten-number-list
(define f latten-number-list
(lambda (s)
(cond
((null? s)
'())
((number? s)
(else
(let ((flatcar
(f latten-number--list
(
(car s))))
append flatcar
(f latten-niiaber-list
(c dr
s))))))))
Program
breai
17.8
(define break
(lambda (x)
i))
Program
17.9
break
(define break
(lambda (x)
(let
(breeik-receiver
(lambda (continuation)
(continuation i))))
(call/cc break-receiver))))
same
list
first
version of
break
is
17.7,
where
Program
17.8.
Hence:
(flatten-number-list '((1
3)
((4 5))
(6)))
(12
4 5 6)
Another way to write break, which uses continuations but has the same
meaning, is given in Program 17.9. This follows because we return as a value
the argument to break. Since that value
560
Using Continuattoru
is x,
we
(lambda
Program 17.10
break
(define breeJc
(lanbda (x)
(let
(bresJt-receiver
(leuDbda (continuation)
(continuation x)))
(amy-action x))))
(call/cc brezJt-receiver))))
Program
any-action
17.11
(define any-action
(lambda (x)
(writeln x)
(get-back)))
Program 17.12
any-action
(define any-action
(lambda (x)
((escaper (lambda
x)))
()
(get-back)))
(x) x).
characterize
call as
the
it left off.
We
do
not notice anything about the pause taking place because the continuation
invocation happens immediately. But that
Program
17.10,
action, which
we
is
defined in
action whatsoever,
is
we may
Program
rewrite
it
happen?
in
561
Program
break
17.13
(lambda (z)
(let ((break-receiver
(lambda (continuation)
(set! get-back continuation)
(any-action x))))
(call/cc break-receiver))))
is
it
at the prompt.
no.
is
Is
yes.
Below
is
we can
tools.
[2]
(get-back)
2
[3]
(get-back)
3
[4]
(get-back)
(1 2 3)
We
limitation.
Unfortunately, that
is
There
is
is
is
Then
[1]
the
[2]
(get-back 4)
562
Using Continuations
Program 17.14
any-action
(define breeJc-argunent
"
any value")
(define smy-action
(lambda (x)
(set
bresJt-argxment x)
((escaper (lambda
()
x)))))
(get-back 5)
[3]
(get -back 6)
[4]
(4 5 6)
Why
is
previous experiment?
continuation,
we
By
was (1 2 3)
for a value,
in the
The computation
prompt.
at the
We
5,
it
We
we note
Program 17.15 that smy-action is not strictly necessary and can be included in the definition of break-receiver. The procedure
break is an interesting program. It is very useful for interactive debugging.
For example, by changing the argument to break, we can construct a mechanism for accessing and modifying part of the local state at the point of the
Finally,
in
dures such
IS
(lambda
In this case,
if
is
locally
x) or (lambda (v)
bound
(set! x v))
list
composed of these two procedures gives a lot of power to affect the internal
Program 17.16 shows how flatten-number-list
changes to support break. Whenever breaJc occurs, breaOt-ao-giunent gets
bound to a two-element list and we define the extract and store procedures
state of a computation.
as
shown
This
able.
is
in
17.18.
We
lists
number of
of arbitrarily
many
variables increases.
If
563
Program 17.15
break
(lambda (z)
(let ((break-receiver
(lambda (continuation)
(set! get-back continuation)
(set
break-argument x)
((escaper (lambda
()
x))))))
(call/cc break-receiver))))
Program 17.16
flatten-number-list
(lambda (s)
(cond
((null?
(
'())
s]
(number? s)
(list
(break
(list (lambda
()
(lambda (v)
s)
(set! s v))))))
(else
(let ((flatcar
f latceir
Program 17.17
extract
(define extract
(lambda
()
breatk
564
many
variables,
it
Using Continuations
Program 17.18
store
(define store
(laabda (value)
((2nd break-eurguaent) value)))
is
Exercises
llatten-nuober-list
Consider the new definition of flatten-number-list below. What changes
are needed to make the sequence of invocations to get-back in the first experiment produce the same result? How about for the second experiment?
Exercise 17.4:
(define f latten-nuaber-list
(laBbda (s)
(letrec
((flatten
(laabda (s)
(cond
((null? s) '())
((nuBber? a) (break (list s)))
(else (let ((flatcar (flatten (car s))))
(append flatcar (flatten (cdr s) ))))))))
(flatten s))))
Exercise 17.5
Consider how we can repeat the results of the
number-list of Program
17.16.
first
is
that
no number may be input from [2] to the end of the experiment. Hint: Do
not use store.
Exercise 17.6:
product*
Each time
it
and
565
as
had been a
the
if
1.
more than three zeros are found, then the result is "error: too
many zeros." This is actually a form of exception handling where finding
the
corresponds to an exception and finding the fourth
corresponds to an
prompt.
error.
If
Experiment with
different
(define product+
(lambda (n Is)
(letrec ((product
(lambda (Is)
(cond
((null? Is)
1)
n (product Is)))))
Experiment with
(product+ 5 '((1 2) (3 4) (0 6) (7 0)))
(product+
Exercise 17.7:
'((1 2)
(2
(0 3)
((0
5)
0)
0)))
break-var
var)
Exercise 17.8
Consider the following experiment:
[1]
(f latten-number-list
'((1 2) 3))
[2]
(get-back 4)
2
[3]
(f latten-number-list
566
Using Continuations
'((5 6 7) 8))
Why
is
the variable
these results.
[4]
(get -back 7)
6
[5]
(get-back 8)
7
[6]
(get -back 9)
8
[7]
(get-back 10)
(7 8 9 10)
[8]
(get -back 5)
3
[9]
(get-back 6)
(4 5 6)
Exercise 17.9
Consider the results of the experiment from the previous exercise.
the results differ
if
the
list
like
How would
a queue instead
of a stack?
There are
lots of
We
next look at a
we look
at
coroutines.
is
It is
sent
Before
called coroutines.
is
When
In this
information
dure becomes dormant, and the dormant procedure, the one receiving the
information, becomes the active one.
One
playing.
Each player
Let us
first,
game
name
is
these
567
This
is
them
accomplished by including
as
it
indicates a
in the
dice). Similarly, the code for B includes (resume C dice), and the code for
C includes
processing where
is
the
first
it left off.
control flow
is
As a
result,
game
simulation.
If
would require
Remember
that nothing
Now
[1]
is
if
we invoke
'*)
(A
we
all
of
its
'*)
(A
This is A
This is B
This is C
Came from
Back in A
Came from A
Back in
Came from
Back in B
Came from B
it
takes to
make
We
argument
invoked.
From
is
The
variable v
these examples,
is
we
In fact,
it
of
little
see that
We
concern.
resume
When resume
is
it is
necessarily
must look
invoked,
it
gives up control to
when someone
resumes
else
it
it.
are first class, not only can they be passed as the required
in
when
whomever
This
is
like
a pro-
resuming and
(Since coroutines
first
argument to
to resume.)
The
first
568
Using Continuations
is
is
Program 17.19
game
(define A
(let ((A-proc (lambda (resume v)
"
(resume B "A"))
"
(resume C "A")))))
(coroutine-mciker A-proc)))
(define B
(let ((B-proc (lambda (resume v)
"
(resume C "B"))
"
(resume A "B")))))
(coroutine-meiker B-proc)))
(define C
(let ((C-proc (leimbda (resume v)
"
(resume A "C"))
"
(resume B "C")))))
(coroutine-maJcer C-proc)))
formed so that
time,
is
initially true.
procedure
is
the binding of resume and v in the programs above takes place. Subsequent
structure of resumer
n.6
some other
coroutine.
Basically, the
is
569
Progreun 17.20
coroutine-meJcer
(define coroutine-maker
(leuabda (proc)
(lambda (v)
(set! saved-continuation v))))
(first-time ft))
(leimbda (value)
(if first-time
(begin
(set! first-time if)
Program
17.21
resune-malcer
(define resume-mciker
(lambda
update -proc
(update-proc! continuation)
(next-coroutine value))))
(call/cc receiver)))))
(cadl/cc receiver)))
Thus
ated. In
coroutine-maker,
done
(resume-maker update-continuation
When resumer
is
in the
!
B,
570
a continuation
is
For example,
if
Using Continuations
is
A,
then the
When
A.
in the
the updating
is
"V"
is
sent to coroutine B. B
its
resumer.
Exercises
Exercise 17.10
To clarify
variables.
we used many
essary.
as possible.
Exercise 17.11
Look
it
If
there
is
a first-time
flag,
variable.
Exercise 17.12
(display "ping-")
(resume pong 'ignored-ping))))
(coroutine-maker ping-proc)))
(define pong
(let ((pong-proc (leunbda (resume v)
(display "pong")
(newline)
17.7 Grune's
(pong '*))?
Problem
Now we
The problem
is
described as follows:
1 7.
571
And we
If
in series
c,
as does baa.
up
instead.
Now we
c.
as:
Input
we can think
have
we
will
Output
left
and
from
left
to right. This
is
for
Output to
the user.
It
display.
B because
for A
is
now
is
to give control
where x
an
is
a.
is
A cannot pass
The only
also sent to A.
Now
and y
is 6
in question,
is
bound
along to
(respectively, c):
XX =^
2.
3.
'ok)))
is
1.
=^
it
possible alternative
a (respectively, b)
(eq? symbol-2 i)
(resume right y)
(begin
(resume right symbol-1)
(resume right symbol-2))))
572
a,
B.
symbol
something to
cis
in control. If the
It
Using Continuations
Program 17.22
reader
(define reader
(lajBbda (right)
(cycle-proc
(lambda
(resume right (prompt-read "in> ")))))))
(coroutine-meiker co-proc))))
In order to replace aa by
order to replace 66 by
is
is a,
is 6,
is 6,
is c,
left
left
is
is A,
and right
is
differs
If
c,
6,
from
x,
that symbol
send
is
it
the
along to right.
same
as the
first,
If not, get
is B;
in
Output. Here
If
that symbol
send y to right.
If it differs,
send both
The
action of Output
(i.e., B).
If it finds
Output action
is
simple.
halts.
It
If not, it
is:
'ok)))
(escape-on-end symbol)
(writeln "out>
The
"
symbol)))
its
it
read after
first
displaying a prompt:
all free
it is
make
The
is
forming the coroutines are given in Programs 17.22, 17.23, and 17.24.
We still have the task of building the wires into the communication channels.
We are now going to use letrec to create the mutually recursive coroutines
Input,
A, B,
letrec expression to
work:
J 7.
7 Grune
's
Problem
573
Program 17.23
writer
(define writer
(lEunbda (left escape-on-end)
(cycle-proc
(lambda
()
(escape-on-end 'end)
(writeln "out>
"
symbol))))))))
(coroutine-maker co-proc))))
Program 17.24
x->y
(define x ->y
(cycle-proc
(lambda
()
ok)))
x)
(resume right y)
(begin
(resume right symbol- 1)
(resume right symbol-2))))
(resume right symbol-!)) ))))))
(coroutine-maker co-proc))))
(letrec
((Input (reader A))
(A (x->y 'a
(B
'b
Input B))
(Output 'ok))
Each of Input,
A, B,
and Output
is
built
574
Using Continuations
Program 17.25
grune
(define grune
(laabda
(let ((grune-receiver
(laabda (escape-grune)
(letrec
((Input (reader (lambda (v)
(A v))))
(A (x->y
'a
'b
(B (x->y
'b
'c
(B v))
(v)
escape--grune)))
(Output 'ok)))))
(call/cc gnme-receiver) )
Input,
A, B,
is
the problem.
All of the
procedures are being created at the same time as they are being passed as
A,
and to create
A,
we need
Input. To solve this problem, we must freeze the coroutines that are argu-
ments
in the
we
we
get the
(i.e.,
wrong
arity; that
is,
if
(letrec
((Input (reader (lambda (v) (A v))))
(A (x->y 'a
'b
(x->y 'b
'c
(B
(Output 'ok))
Program 17.25 shows the final definition of grune with all the necessary
v)). In the exercises, we develop a more natural
uses of (lambda (v) (
way to think about this unusual behavior.
i 7.
575
Exercises
wrap
Exercise 17.13:
Consider the special form wrap, which has the following syntax table entry:
(wrap proc)
when args
This works
in all cases
expression.
but one:
is
capture.
Exercise 17.14
Using the results of the previous exercise, write the syntax table entry for
is
known
variable capture
Is free
still
problem?
Exercise 17.15
Using the results of the previous exercise, redefine gnine using wrap.
safe-letrec
Exercise 17.16:
form
is like
is
side variable
is
wrapped
also appears as a left-hand side variable. Using the results of the previous
definition of
to
(wrap proc) to
(define gnine
(lambda
()
(safe-letrec
((Input (reader A))
(A
(B
(Output 'ok)))))
(call/cc grune-receiver))))
576
Using Continuations
Exercise 17.17:
process-msLker
(lambda (v)
(set! saved-continuation v))))
(let ((resumer (resume-maJcer update-continuation!))
(first-time #t))
(leuabda (value)
(if first-time
(begin
(set! first-time #f)
(cycle-proc
(lambda ()
(f resumer value))))
(saved-continuation value))))))))
Exercise 17.18
Using the results of the previous exercise, explain how process-maker
differs
is
a corou-
Exercise 17.20
Redesign the solution of the Eight Queens problem using coroutine-maker
so that each queen
is
a coroutine.
Exercise 17.21
pairs. Hint:
else
unchanged.
Exercise 17.23
577
17.8 Final
Thoughts
We
continuations, but
tions can be used.
all
we have tried to show you some of the ways that continuaMost of the time, you should be content to solve problems
And
object-oriented programming.
The
is
even
tricks.
less
The computer's
role has
been much
would happen
if
If
What
you are
the procedure
(lambda (x) (+ x 1)) with the procedure (lambda (x) (- x 1))? This
book has been about ideas and how we can combine separate categories of
some emphasis
has been placed on how fast the computer determines the value of a computation, we have tried to approach the ideas in this book more in terms of
capturing the essence of a computation. Subtle issues of efficiency can come
much later. We have challenged you at every turn. Each piece of the computational puzzle fits together and is described in terms of simple ideas. Under
our guidance, you have entered the universe of computer science. It was our
ideas to create procedures that do our computing. Although
goal to cause you to look forward to future explorations into this fascinating
field.
PROBLEMS
Problems worthy
of attack
578
Using Continuations
Al
Set
Q
R
DC4
ENQ
NAK
ACK
SYN
&
BEL
ETB
BS
CAN
HT
EM
A(10)
LF
SUB
B(ll)
VT
ESC
C(12)
FF
FS
<
D(13)
CR
OS
NUL
DLE
SP
SOH
DCl
STX
DC2
II
ETX
DCS
EOT
E(14)
SO
RS
F(15)
SI
US
>
7
}
~
"
n
-
DEL
A1.2 Abbreviations
NUL
SOH
STX
ETX
EOT
ENQ
A1.3
How
to
for
Control Characters
device control
end of text
DCl
DC2
DCS
DC4
end of transmission
NAK
negative acknowledge
enquiry-
SYN
ETB
synchronous
CAN
EM
cancel
null
start of
heading
start of text
ACK
acknowledge
BEL
bell
BS
backspace
device control 2
device control 3
device control 4
idle
HT
horizontal tabulation
linefeed
SUB
ESC
substitute
LF
VT
vertical tabulation
FS
file
FF
form feed
carriage return
SO
shift
GS
RS
US
group separator
CR
SI
shift in
SP
space
DLE
DEL
delete
out
escape
separator
record separator
unit separator
for the
for
Information Interchange.
(Scheme now supports the broader International Character Code.) The number at the top of a column represents the
left
of a
first digit,
digit of the
at the
is
used to represent the character in that row and column. Thus the hexadeci-
mal code
G, which
is
in the
letter g is 67,
4*^^
and
column and
for
is
row,
is
47.
The
7*'^
580
References
Abelson, Harold, and Gerald J.Sussman, with Julie Sussman. 1985. Structure and
Interpretation of
MIT
Press and
New York,
MA: MIT
Press.
1987.
Cliffs,
NJ: Prentice-Hall.
Eisenberg, Michael.
1988.
Programming
in
Scheme. Redwood
CA:
City,
Scientific
Press.
Feller,
WiUiam.
Vol.
1.
New
An
1950.
Friedman, Daniel
P.,
York,
Applications,
and Matthias FeUeisen. 1988. The Little LISPer, Third EdiEdition, Cambridge, MA: MIT Press.
view of coroutines. In
Mind and
its
Sons.
Pattern.
New
MA: MIT
Press.
York,
NY:
12(7):75-81.
the Essence of
Many Keyboards.
In Case
Alumnus.
67(8):2-7.
their
com-
find.
W.
MUler.
1988.
Communications of
the
1986.
The
Frege to Godel,
On
1924.
2l(l2):37-79.
LISP
An
report on the
revised
MA: Harvard
In
From
Edited by Jean
Introduction to Scheme.
New
York,
NY:
Prentice-Hall.
Guy Lewis, Jr., and Gerald Jay Sussman. 1978. The revised report on
Scheme, a dialect of Lisp. Memo 452, MIT Artificial Intelligence Laboratory.
Steele,
Sussman, Gerald Jay, and Guy Lewis Steele Jr. 1975. Scheme: an Interpreter for
Extended Lambda Calculus. Memo 349, MIT Artificial Intelligence Laboratory.
Texas Instruments. 1988.
Redwood
582
References
City,
PC
CA: The
Scientific Press.
&
Index
#f 23
all-SEune?, 57
#t, 23
alpha-search, 330
#\newline, 497
Alternative, 40, 42
#\return, 497
#\space, 497
*,
andmap, 208
74
*-and-count-maker, 547
',
Annihilator, 247
10
answer-maker, 531
any-action, 561, 563
append! 368
append, 96
append-to-list-of-zeros, 155
+,74
-.74
/.
74
<,
76
<=, 76
Application, 38
75
=, 26,
>,
andmap-c, 216
Apply, 38
76
>=, 76
apply, 200
=>,
apply-procedures, 511
apply-to-all, 213
Argument, 15, 31, 33
arrival -time -generator, 427
20
Abelson, Harold,
5,
581
abs, 76
Abstract data, 90
acc-max, 394
ASCII, 580
asin, 76
assoc, 346
at-least-one, 233
atan, 76
Atomic, 101
attempt, 553, 554
addl, 74, 75
backtrack, 186
adjoin, 250
Backward
Algorithm, 31
Base, 156
all-integers, 494
substitution, 116
Base case, 48
base->decimal, 161
base-object, 389
cardinal, 242
between?, 216
between?-c, 216
Binary numbers, 156
binary-product, 161
Binary relation, 258
Binary search, 329
binary->decimal, 156, 161
binary-search, 330
binary-sum, 161
cartesian-product, 258
Bind, 9
Bit, 155
blanks, 191
Boolean, 23
boolean?, 24
both, 231
variable, 9
Box, 386
Branch, 108
break, 560-563
break-var, 566
Bronowski, Jacob,
Bucket, 410
581
bucket-maker, 410
build-solution, 185
build-streeun, 487
Byte, 155
.r, 21
CaU, 38
call, 531
call/cc, 527
call-with-cxirrent-continuation,
515
calls-fib, 128
Capturing, 464
584
Cdr
pointer, 360
ceiling, 76
char->integer, 496
char-ci<=?, 498
char-ci<?, 498
char-ci=?, 498
char-ci>=?, 498
char-ci>?, 498
char-lower-case?, 498
char-upcase, 498
char-upper-case?, 498
char<=?, 497
char<?, 497
char=?, 497
char>=?, 497
char>?, 497
cdr, 20
Character, 496
key, 410
ca.
cd...r, 21
cheir-downcase, 498
Bottom-up, 37
Bound
case, 384
list,
marker, 403
head, 405
circular-list-maker, 405
Clause, 40, 41
Clinger, William,
5,
581
close-enough?, 168
close-input-port, 501
close -output -port, 503
closest-common-supervisor, 337
Closure, 135
Coefficient, 142
car, 20
combine, 419
Compatible, 298
compose, 201, 511
Index
32, 581
403
compose-many, 206
composes, 206
Computer, 6
Concatenating, 163
Define expression, 9
Delayed
Condition, 40
delayed-list-accumulate, 481
delayed-list-car, 477
delayed-list-cdr, 478
delayed-list-cons, 479
delayed-list-null?, 478
delayed-list-product, 481
delayed-list-sum, 481
delegate, 388
Constructor, 14
Delegation, 391
compound, 42
simple, 42
Conditional expression, 40
cons, 14
Consequent, 40, 42
Constant, 10
contains, 241
Context, 515, 516
list,
double, 419
multiple, 419
denr, 84, 91
depth, 110
coroutine-maker, 568
Dequeuing, 399
Derived keywords, 449
describe, 70
cos, 76
count-all, 102
count -backgroiind, 83
count-background-all, 114
coiint-chars-to-next-space, 508
count-parens-all, 114
countdown, 553
diagonal, 495
difference, 243
digits->poly, 156
display, 170, 503
display-tower-of-hanoi, 182
divides-by, 492
Counter, 390
do, 471
Documentation, 35
Domain, 258
domain, 258
coiint-pairs, 373
customer-maker, 436
Dot-product, 276
decimal->base, 161
decimal->binary, 159, 161
decimal->hexadecimal, 160
decimal->octal, 160
Echo, 174
efface, 371
Eight Queens problem, 183
Declare, 450
Eisenberg, Michael,
decr-ints, 327
element, 240
Deep
Ellipsis, 33,
procedure, 103
else, 40
recursion, 103
Empty
Empty
deep-recur, 227
deepen-1, 101
define, 9
Index
5,
581
37
list,
14
set,
236
empty-set?, 249
empty?, 343
585
end-of-sentence?, 507
end-of-stream?, 484
Enqueuing, 399
Enter, 10
FIFO, 399
entering, 61
Environment
f ile->stream, 504
f ibonacci-numbers, 491
Field, 323
eof-object?, 502
file-copier, 504
filter-in-all, 224
f ilter-in-all-c, 224
f ilter-in-c, 222
filter-out, 223
filter-out-all, 228
find-supervisor, 337
f inite-stream->list, 485
eq?, 26
equivalence-relation?, 263
Flat
global, 130
initial global,
local,
129
130
model, 48
nonlocal, 131
eqv?, 27, 75
error, 199
first-group, 36
irsts-of-both, 39
procedure, 95
recursion, 95
even?, 98
exp, 76
Flowchart, 431
exponent, 202
for, 470
f or-all, 239
f or-each, 197
eiponential-randon-variable, 427
Expression, 7
f or-one, 248
Evaluate, 8
even-positive-integers, 486
conditional, 40
eipt, 76
force, 457
formatter, 505
Free, 130
extreme-value-c, 216
Friedman, Daniel
f orwiird, 185
581
Fulfillment, 457
fact-it, 118
Function, 259
function-compose, 262
function?, 260
Functional programming
style, xx,
family-intersection, 246
fib-it, 124
gallons-generator, 428
Garbage collection, 364
gas-station-simulator, 440
Gauge, 393
gauge-maker, 394
Fibonacci, 120
Greatest
f junily-union, 246
Felleisen, Matthias, 5, 581
586
Index
common
divisor, 93
357
grune, 575
integers-from, 493
interactive- square-root, 175
intersection, 243
inverse-relation, 262
Invoke, 38
gcd, 93
190
is-divisible-by?, 217
Halting problem, 382
Iterative, 71
harmonic-sum, 77
harmonic-sum-it, 120
Hash
process, 117
juggle, 39
function, 414
hash-function, 500
hash-table-malcer, 414
has-prime-divisor?, 493
Head, 405
Hein, Piet, 578, 581
derived, 449
Keyword
list
begin, 472
Hexadecimal, 159
hexadecimal->decimal, 160
Higher-order procedures, xx
Hofstadter, Douglas R., 178, 581
rule,
Keyword,
and, 466
Helping procedure, 36
Horner's
Key, 323
beginO, 472
break-vaur, 566
case, 384
cond, 40, 472
149
cycle, 462
hoH-many-till, 542
define,
9,
32
Identity, 247
delay, 457
if, 41
delayed-list-cons, 479
one-armed, 42
do, 471
Imperative programming
else, 40
351
Implicit begin, 166
for, 470
index, 82
freeze, 451
Inheritance, 388
Initial condition,
Initial global
Input device,
if, 41
125
environment, 129
6
lambda, 32
let, 132, 459
let*, 467
insert, 304
macro, 451
insert-double-spaces, 507
insert-left, 100, 223
insert-left-all, 108, 141
insert-newlines, 508
insert-right, 100
insert -right -1st, 55
named
repeat, 470
safe-letrec, 576
set!, 341
insertsort, 304
Instances, 387
stream-cons, 482
variable-case, 473
while, 469
Integer, 73
integer->char, 497
integer?, 74
Index
let, 469
quote, 10
wrap, 576
Knuth, Donald
E., 3
587
lambda, 32
lower!, 499
xvi, 32
last-item, 46
last-pair, 368
Leading
macro, 451
Macrocode, 452
Macroexpansion, 452
MacScheme,
xxiv, 5
make-groups, 310
make-list, 82
make-list-of-one, 34
make-list-of-two, 35
make-promise, 457
make-ratl, 84, 91, 92
make-relation, 262
make-set, 237
make-string, 498
make-term, 144
make-vector, 270
coefficient, 143
term, 143
leading-coef 144,
leading-term, 144
,
151, 152
Leaf, 108
leaving, 61
leftmost, 115
Legal, 183
legal?, 184
length, 78
named, 469
map-first-two, 207
map2, 208
marker, 404
Marling, William,
LIFO,
mat+, 301
quoted, 18
list, 37, 199
list->delayed-list, 481
list->set, 247
list->stream, 484
list->string, 498
list->vector, 270, 273, 284
list-front, 83
list -linear-search, 331
list-of-f irst-items, 55
list-of-symbols?, 57
list-of-zeros, 78
list-ref 80, 142
3,
581
Matrix, 290
matrix, 300
matrix-generator, 295
matrix-multiply-by-scalar, 301
matrix-product, 299
matrix-ref 294
matrix-set!, 300
matrix-transpose, 296
matrix-view, 301
,
max, 76, 88
memq, 50
log, 76
memv, 50
Logical, 23
merge, 98
lookup, 346
Mergesort, 309
Literal value, 10
588
lookup2, 358
lower, 499
Index
object-maker, 474
occurs, 128
occurs-it, 128
natural, 309
mergesort, 328
Message, 386
message, 553
Message-passing
Octal, 159
style,
387
Methods, 386
Miller, Keith W., 324, 581
octal->decimal, 160
odd-positive-integers, 489
odd?, 98
One-armed
min, 76
Minsky, Marvin
L.,
581
mk-asc-list-of-ints, 128
mk-desc-list-of-ints, 128
modulo, 76
Monomial, 144
Monte Carlo methods, 426
mult-by-n, 82
if,
42
One-to-one, 262
one-to-one?, 262
open- input -file, 501
open- output -file, 503
Operands, 11, 14
Operator, 33
arithmetic, 11
mult-by-scalar, 222
multiple?, 83
multiples-of 493
multiply-by-scalar, 274
Mutation, 282
Mutators, 282
or-proc, 464
Mutual
Ordered
recursion, 99
n-tuple->integer, 84
Named
let,
469
Order, 126
exponential, 126
126
linear,
ormap-c, 216
Output
Output
device, 6
p*, 147
Pair, 22, 24
Nesting
level,
101
new-escaper, 541
newline, 170, 503
Node, 108
none, 237
Nonlocal, 131
null?, 25
num-cols, 293
num-rows, 294
Number,
port, 500
p+, 145
P-, 147
dotted, 22
pair-merge, 311
pair?, 24
pairwise-sum, 81
palindrome?, 165
Parameter, 32
Park, Stephen K., 324, 581
partial, 223
partition, 320
pascal-triangle, 357
Pass by value, 38
PC Scheme, xxiv, 5
pick, 249
number?, 23
Numerical vector, 274
numr, 84, 91
plus, 202
Index
255
ormap, 209
poly->digits, 158
poly-cons, 144, 151, 152
589
poly-quotient, 154
poly-remainder, 154
poly-value, 149
Polynomial, 143
Quicksort, 316
quicksort, 316
quote, 10
pop
Quoted
343
Port
list,
18
quotient, 76
Quoting, 10
input, 500
output, 500
r-, 86
r/, 86
r<, 87
r>, 87
Prefix, 32
rabs, 92
notation, 11
95
mutation, 282
procedure?, 25
process-maker, 577
product+, 544-547, 565
product, 213
product-all, 228
Program, 8
Programming
r+, 85
r=, 86
Predicate, 23
flat,
r*, 86
style
Prompt, 8, 174
prompt-read, 440, 444
Pseudo-random number, 324
pump-maker, 434
push! 343
read-char, 502
read-demo, 174
Read-eval-print loop, 8
reader, 573
Real numbers, 73
real?, 74
Receiver, 527
receiver, 557
receiver-1, 530
receiver-2, 530
receiver-3, 530
receiver-4, 539
Record, 322
Recursion, 46
Quantifiers, 231
deep, 103
queens, 189
Queue, 399
fiat,
front, 399
rear,
399
queue->list, 401
590
Index
95
mutual, 99
Recursive process, 117
reduce, 207
Rees, Jonathan,
5,
582
Reflexive, 262
reflexive?, 262
regroup, 36
rpositive?, 87
rprint, 89
rzero?, 85
Relation, 258
relation-compose, 263
relation?, 262
Relational calculus, 332
remainder, 76
remove, 100
remove-lst, 52
remove-lst-trace, 61
remove-2nd, 56
remove-all, 104
remove-all-c, 228
remove-extra-spaces, 505
remove-last, 56
remove-leftmost, 113, 137
remove-newlines, 506
remq-lst, 53
remq-all, 105
remv-lst, 53
remv-all, 105
repeat, 470
replace, 56
report, 437
reset, 199, 526, 540
reset!, 386
residue, 250
s-and-n-list, 43
saf e-letrec, 576
same-sign?, 92
sandsich-lst, 56
Scalars, 274
Scope, 131
lexicsd,
binary, 329
329
searcher, 188
linear,
Searching, 303
second, 39
second-group, 36
select-by-cardinal, 254
Selector, 20
service-maker, 437
set!, 341
set->list, 247
set-builder, 244
set-builder-map, 339
set-equal, 239
set-equal?, 239
shov, 386
resiime-maker, 569
reverse, 97, 126
sieve, 492
131
Search
set-map, 247
set?, 249
Sets, 236
Side
efl"ect,
60
Simulation, 425
simulation, 433
simulation-setupftrun, 433
rmin, 88
sin, 76
rminus, 92
Root, 108
Singleton, 44
round, 76
smudge, 372
roH-of 295
,
Index
singleton-list?, 44
5,
582
Sort
insertion, 303
591
key, 323
string<?, 322
string=?, 164
string>=?, 322
mergesort, 309
natural mergesort, 309
quicksort, 316
string>?, 322
string?, 163
Sorting, 303
Special form,
9,
subl, 75
38
sqrt, 76
square-root, 169
square-root-display, 171
squares-of-integers, 493
Stack, 342, 396
Standard-output, 500
State, 285, 356
variables, 356
station-maker, 433
Steele, Guy Lewis Jr.,
subrelation/lst, 259
subset, 241
subst, 100
subst-lst, 54
subst-all, 107
subst-all-m, 216, 228
Substitution model, 48
substq-all, 107
substring, 163
substring-ref 165
substring?, 164
subtract, 206
,
5,
582
store, 565
Subtree, 108
store!, 417
successive-posers, 289
stream-filter-out, 489
stream-map, 488
stream-member?, 494
stream-null?, 484
streeun-plus, 489
stream-ref 494
stream-times, 489
super, 202
super-order, 204
superduper, 204
superset, 241
Sussman, Gerald Jay, xv,
Sussman, JuUe, 5, 582
sap!, 386
swap-maker, 286, 287
swapper, 66, 139, 335
swapper-c, 215
swapper-m, 214
switch, 40
5,
string, 498
string->list, 498
string-append, 163, 499
string-ci=?, 164
string-insert, 164
string-length, 163, 498
string-ref 498
string-reverse, 165
string-set 498
string<=?, 322
Symbol, 6
symbol->string, 164
symbol?, 24
Symbolic algebra, 142
Symmetric, 262
symmetric-difference, 254
symmetric?, 262
Syntax table, 453
table entry, 455
592
Index
Tag, 249
Tagged
582
list,
249
pair,
278
procedure, 285
tan, 76
Term, 142
Terminating condition, 48
test-tracing, 72
tester, 557
TgX
typesetting, xxiv
thas, 456
the-empty-set, 249
the-null-delayed-list, 478
the-null-streUB, 484
the-zero-poly, 144, 151, 152
theater-maker, 418
there-exists, 238
third, 39
Thunk, 174
timer, 325
timer*, 359
timer2, 358
times, 202
Top-down, 37
Top-level, 17, 101
tracing, 71
Transformer, 453
Transitive, 263
transitive?, 263
Transpose, 296
Traverse, 108
Tree, 108
recursion, 103, 311
trim-spaces, 505
True, 23
truncate, 76
Turing, Alan M., 381
Turing machine, 381
tapes, 375
type, 386
type-of 40
union, 243
Universe, 236
unlist, 332
8,
260
value, 260
Variable, 7
veuriable-case, 473
vec*, 275
vec+, 275
Vector, 267
vector, 271
vector->list, 276
vector-accvimulate, 276
vector-append, 290
vector-apply-elementwiseto-both, 274
vector-change!, 315
vector-copy, 272
vector-generator, 279, 280, 283
vector-insert !, 307
vector- insert sort 305
vector-length, 279
vector-linear-search, 290
vector-map, 273
vector-memoize, 350
vector-merge 313
vector-mergesort 314
vector-product, 275
vector-quicksort!, 319
vector-ref 279, 280
vector-reverse, 285, 290
vector-reverse!, 287
vector-stretch, 271
vector-sum, 275
vector-swap!, 320
vector-update, 272
vector-update!, 283
vector-vies, 289
,
vector?, 279
vien, 268
unif-rand-var-0-1, 426
Uniform distribution, 426
Index
while, 469
while-proc, 353
word-frequency, 413
593
writer, 574
Rrap, 576
wrapa, 83
write, 173, 503
^_^
"'
write-char, 504
Zero based, 79
writeln,
zero-poly?, 144
zero?, 74
57, 199
writeln/retum, 531
594
'''^^'
Index
'/
//
Scheme and
In/
Scheme
tics,
is
Its
clear
seman-
and functions.
gramming are
Among
the examples used to illustrate object-oriented prolists, hash tables, and a gas station
simulation.
McGraw-Hill Edition