Massachusetts Institute of Technology

Department of Electrical Engineering and Computer Science

DON’T PANIC

A 6.001 User’s Guide to the Chipmunk System

Spring Semester, 1989

by Arthur A. Gleckler, with contributions by Hal Abelson, Todd Cass, Chris Hanson, Jonathan Rees, Richard Stallman, Kevin Theobald, and a cast of thousands

This manual is an introduction to the Scheme system on the Hewlett-Packard 9836 computer (the “Chipmunk”) for students taking 6.001—Structure and Interpretation of Computer Programs.

We strongly suggest that you glance through this manual at the beginning of the semester in order to get a general overview of the system. A little time spent learning the basics will save you hours working on problem sets. Bring the manual with you for reference while you work on 6.001 computer assignments.

First, read chapter 1—this describes the setup of the Scheme system on the Chipmunk. Chapter 2 describes Edwin, the program editor. Most of the editor commands are the same as those in Emacs on Project Athena. Chapter 3 describes the special Scheme software for finding and correcting errors in your programs. Read the introduction to that chapter now, but postpone reading the rest until later in the semester. Chapter 4 is a Scheme reference manual; use it when you need detailed information about the operation of Scheme, particularly its built-in procedures.

Important

Do not turn off a 6.001 computer! There is a good

chance that you will blow a circuit breaker in the lab, wiping out your Chipmunk other people’s work on other Chipmunks. If your computer seems stuck, do not try to fix things by turning the machine off and back on.

Be sure to log out when you are through using the computer. Logging out ensures that the work you have done is saved on your floppy disk, and prepares the Chipmunk for the next person who will use it.

Contents

1 Overview 1

1.1 Parts of the Chipmunk Universe . . . . . . . . . . . . . . . . . 1 1.1.1 Scheme and Edwin . . . . . . . . . . . . . . . . . . . . 2 1.1.2 Typing editor commands at the keyboard . . . . . . . . 3 1.1.3 Buffers and files . . . . . . . . . . . . . . . . . . . . . . 3 1.1.4 The Scheme interaction buffer, and evaluating Scheme

commands . . . . . . . . . . . . . . . . . . . . . . . . . 4 1.1.5 Disks and files . . . . . . . . . . . . . . . . . . . . . . . 5 1.1.6 Text and graphics . . . . . . . . . . . . . . . . . . . . . 5 1.1.7 Summary . . . . . . . . . . . . . . . . . . . . . . . . . 6

1.2 Using the Chipmunks . . . . . . . . . . . . . . . . . . . . . . . 6 1.2.1 Logging In . . . . . . . . . . . . . . . . . . . . . . . . . 6 1.2.2 Directories and Files . . . . . . . . . . . . . . . . . . . 6 1.2.3 Initializing the Floppy Disk . . . . . . . . . . . . . . . 8 1.2.4 Loading Problem Sets . . . . . . . . . . . . . . . . . . 8 1.2.5 Saving Your Work . . . . . . . . . . . . . . . . . . . . 9 1.2.6 Printing text and pictures . . . . . . . . . . . . . . . . 9 1.2.7 Logging Out . . . . . . . . . . . . . . . . . . . . . . . . 10

1.3 Chipmunk Status Indicators . . . . . . . . . . . . . . . . . . . 11 1.4 Crashes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 1.5 Backing up your disks . . . . . . . . . . . . . . . . . . . . . . 12

2 Edwin, the Editor 13 2.1 Buffers and Windows . . . . . . . . . . . . . . . . . . . . . . . 14 2.2 The Edwin Screen . . . . . . . . . . . . . . . . . . . . . . . . . 15 2.3 Commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

2.3.1 Arguments Optional . . . . . . . . . . . . . . . . . . . 18 2.3.2 Extended Commands . . . . . . . . . . . . . . . . . . . 19

2.4 Trouble . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 2.5 Getting Help . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 2.6 Typing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 2.7 Moving through a Buffer . . . . . . . . . . . . . . . . . . . . . 22 2.8 Correcting Simple Mistakes . . . . . . . . . . . . . . . . . . . 24 2.9 Undo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 2.10 The Region . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 2.11 Kills and Yanks . . . . . . . . . . . . . . . . . . . . . . . . . . 27 2.12 Editing Scheme Programs . . . . . . . . . . . . . . . . . . . . 28 2.13 Scheme Interaction . . . . . . . . . . . . . . . . . . . . . . . . 30 2.14 Search . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 2.15 Replace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 2.16 Buffers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 2.17 Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 2.18 Saving and Loading Files . . . . . . . . . . . . . . . . . . . . . 38 2.19 Directory Edit . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 2.20 Printing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40 2.21 Miscellaneous Commands . . . . . . . . . . . . . . . . . . . . 40

3 Debugging 41 3.1 Subproblems and Reductions . . . . . . . . . . . . . . . . . . . 43 3.2 Debug (The Continuation Browser) . . . . . . . . . . . . . . . 45 3.3 Where (The Environment Browser) . . . . . . . . . . . . . . . 49 3.4 Trace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50 3.5 Break . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52 3.6 Error and Breakpoint Procedures . . . . . . . . . . . . . . . . 55

4 Scheme Reference 57

4.1 Notation and terminology . . . . . . . . . . . . . . . . . . . . 57 4.1.1 Notation for this Chapter . . . . . . . . . . . . . . . . 57 4.1.2 Evaluation . . . . . . . . . . . . . . . . . . . . . . . . . 58 4.1.3 Numbers . . . . . . . . . . . . . . . . . . . . . . . . . . 58 4.1.4 Identifiers . . . . . . . . . . . . . . . . . . . . . . . . . 59 4.1.5 Whitespace and Comments . . . . . . . . . . . . . . . 59 4.1.6 Special Characters in Scheme Notations . . . . . . . . 60

4.2 Variables and bindings . . . . . . . . . . . . . . . . . . . . . . 61 4.3 Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61

4.3.1 Variable references . . . . . . . . . . . . . . . . . . . . 61 4.3.2 Literals . . . . . . . . . . . . . . . . . . . . . . . . . . 62 4.3.3 Procedure calls . . . . . . . . . . . . . . . . . . . . . . 63 4.3.4 Lambda expressions . . . . . . . . . . . . . . . . . . . 63 4.3.5 Binding constructs . . . . . . . . . . . . . . . . . . . . 64 4.3.6 Assignments . . . . . . . . . . . . . . . . . . . . . . . . 65 4.3.7 Sequencing . . . . . . . . . . . . . . . . . . . . . . . . 66

4.4 Definitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66 4.4.1 Top level definitions . . . . . . . . . . . . . . . . . . . 67 4.4.2 Internal definitions . . . . . . . . . . . . . . . . . . . . 67

4.5 Booleans and conditionals . . . . . . . . . . . . . . . . . . . . 68 4.5.1 Boolean operations . . . . . . . . . . . . . . . . . . . . 68 4.5.2 Conditionals . . . . . . . . . . . . . . . . . . . . . . . . 70 4.5.3 Testing for equivalence . . . . . . . . . . . . . . . . . . 72

4.6 Pairs and lists . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 4.7 Symbols . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 4.8 Numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 4.9 Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87 4.10 Vectors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88 4.11 Control features . . . . . . . . . . . . . . . . . . . . . . . . . . 89 4.12 Streams and delayed evaluation . . . . . . . . . . . . . . . . . 90 4.13 Input and output . . . . . . . . . . . . . . . . . . . . . . . . . 92

4.13.1 General Terminal and File I/O . . . . . . . . . . . . . 92 4.13.2 Advanced Terminal and File I/O . . . . . . . . . . . . 94

4.14 Environments and evaluation . . . . . . . . . . . . . . . . . . 96 4.15 Miscellaneous . . . . . . . . . . . . . . . . . . . . . . . . . . . 97 4.16 Advanced Features . . . . . . . . . . . . . . . . . . . . . . . . 98 4.17 Graphics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98 CONTENTS A Glossary 101 CONTENTS CONTENTS 1

This page intentionally not left blank.

Chapter 1

Overview

The 6.001 lab (room 34-501) is shared with 6.004; the left half of the room (as you go in the door) has computers and oscilloscopes for 6.004, and the right half has several dozen Chipmunk computers for 6.001. The printers are on your left as you enter the room.

The 6.001 Chipmunks are divided into four groups. Each group shares a printer and a large disk-drive, which holds the Scheme software and the original copies of problem sets. Your own Scheme programs and your changes to the problem set originals are stored on removable floppy disks. Included with this set of notes were two floppy disks for use in 6.001—one for storing your work and one to use as backup. Always remember to bring your floppy disk when you come to the lab; without it, there is no way to save the work you have done so you can continue working on it the next time you visit the lab.

1.1 Parts of the Chipmunk Universe

Using a new computer system can be very confusing—there are many different programs and parts of programs that relate in different ways, and new users are often confused about which part of the system they are dealing with. This section provides a brief introduction of the different parts of the Chipmunk universe: the Scheme interpreter, the keyboard, the Edwin editor, the text and graphics display screens, disks and files, text printers, and graphics printers.

1.1.1 Scheme and Edwin

The Scheme interpreter takes expressions and evaluates them according to the rules of the Scheme language. The programs you write, the simple expressions you evaluate, all the examples in the 6.001 texbook are Scheme expressions. Later in the semester, we will see how the evaluator works, at least in principle.

If all you ever did was type very simple Scheme expressions, then you could use a system in which one typed characters directly at the interpreter. Indeed, the 6.001 textbook describes interactions with the interpreter as if this were the case. But, in reality, you want to type complex expressions; you want to correct typing errors; you want to store text in files; you want to format text so that it can be read easily; and so on. In the 6.001 system, these tasks are accomplished with the aid of a program called a text editor. So—you never (well, almost never) type at the Scheme interpreter directly. Instead, you use the editor to compose text, and, when you are satisfied with the text you compose, you direct the editor evaluate that text, i.e., to transmit it to the Scheme interpreter. Depending on the particular evaluation command you use, you can direct the editor to transmit to Scheme a single line, a single procedure definition, or a larger chunk of text.

What this means is that there are really two languages that you are using in the lab, and two different kinds of commands you will be typing at the Chipmunks. There is Scheme itself, which performs operations such as “compute the factorial of 137” or “find the 10 element of this list.” Then there are editor commands such as “save this text on the floppy disk” or “move the cursor down 5 lines.”

The editor used in 6.001, named Edwin, is a version of Emacs, the editor used in Project Athena. If you are familiar with Emacs, you will find that essentially all of the basic Emacs editing commands work on the Chipmunks. If you do not know Emacs, you will need to spend some time learning the basic commands. In point of fact, most of the editing you will need to do for 6.001 can be accomplished with only a few simple editing commands, and you will soon become familiar with these. On the other hand, as the semester progresses, it will become greatly worth your while to learn some of the more advanced editing commands; these can save you enormous time at the keyboard. Periodically during the semester, you should reread chapter 2 of this manual and try out some useful commands that you may not have previously noticed.

1.1.2 Typing editor commands at the keyboard

The Chipmunk keyboard contains a number of special keys in addition to the usual alphanumeric ones. Across the very top are two rows of keys, most of them numbered. These keys are also labeled. For example, the key numbered k_{2} is also labeled extend .

At the upper left of the keyboard is a key labeled ctrl . This is used like a shift key, i.e., you hold it down while pressing some other key. Thus, to type ctrl – k_{0} , you hold down ctrl , then press k_{0} , then release both keys. Sometimes, ctrl and shift are used together. For example the command marked on the keyboard as write file is typed as ctrl – shift – k_{0} — hold down both ctrl and shift , then press k_{0} , then release all three keys.

Almost all the Edwin commands you will need to use in 6.001 are typed as one of the labeled keys—either the key alone, the key shifted, the key ctrl-ed, or the key ctrl-shifted. All these possiblities are labeled on keyboard.

One class of Edwin commands that are not on the special keys are Edwin’s extended commands. To issue an extended command, you press the extend key and then type the name of the command, which Edwin will echo at the bottom of the screen. For example, to load the code for a 6.001 problem set you use the Edwin extended command “load problem set”. Press extend ,

then type load problem set and press enter.

For those of you who know Emacs, you will find that Edwin’s editing commands can also be typed in the usual Emacs way. For instance, the command to search for a given text string can be typed on the Chipmunk as k_{5} or (as in ordinary Emacs) as ctrl – S . You can use either style command as you prefer. Chapter 2 documents both styles of Edwin commands.

1.1.3 Buffers and files

As described in chapter 2 below, the editor organizes information in to chunks of text called buffers. In general, you will be working with many buffers at once, and Edwin includes commands for switching between buffers, or even for viewing more than one buffer on the screen at once by splitting the screen into separate areas called windows.

When you tell Edwin to load a file from the disk, Edwin creates a buffer that is associated with this file and loads the contents of the file into a buffer so it can be edited. If there is no file on the disk with the name you specify, Edwin will create an initially empty buffer associated to that file.

When you tell Edwin to save a buffer, Edwin will write the contents of the buffer to a file on the disk. Keep in mind that no information is written to the disk until you tell Edwin to save a buffer. If you log out without saving your buffers, the contents of these will be lost. When you do log out, Edwin will notice if there are buffers that you have modified but not saved, and ask you if you want to save them before logging out.

1.1.4 The Scheme interaction buffer, and evaluating Scheme commands

In addition to the buffers associated to your files, there is a special buffer called the Scheme interaction buffer. Whenever Scheme evaluates an expression, the result is placed in the Scheme interaction buffer.

In an ordinary 6.001 session, you type short Scheme expressions in the Scheme interaction buffer, tell Edwin to evaluate these expressions (i.e., send them to the Scheme interpreter). The result returned by Scheme appears right below where you typed. To evaluate an expression, you press the execute key, located at the lower right of the keyboard. Pressing execute tells Scheme to evaluate the expression immediately preceding the cursor.

Do not confuse execute with enter , which located at the right of the keyboard, in the middle. enter does not evaluate a Scheme expression, Instead, it moves the cursor to the next line. You use enter in typing multi-lined expressions. (On the other hand, enter is used in issuing Edwin extended commands.)

You can evaluate Scheme expressions typed in any buffer, not just the Scheme interaction buffer. The only thing special about the intecation buffer is that the values returned by Scheme are placed here automatically. If you wish, you can save the Scheme interaction buffer in a file, edit it, or print it to obtain a transcript of your session with Scheme.

In addition to the Scheme interaction buffer, you will ordinarily open up another buffer in which you type procedure definitions, and save this buffer in a file on your disk. You will evaluate expressions from this buffer, either one expression at a time, using execute , or in larger chunks, such as groups of procedure definitions or even evaluating the entire buffer at once. (See chapter 2) for a description of Edwin’s evluation commands.) In each case, the result of the evlaution will appear in the Scheme interaction buffer.

1.1.5 Disks and files

Your personal files are stored on a floppy disk. In general, you use Edwin commands to interact with files. Edwin has commands for saving the contents of a buffer in a file, and for reading a file from the disk into a buffer, so it can be edited.

There is also a Scheme command called load that takes a file (which had better be a file of Scheme programs) and loads it directly into the Scheme interpreter without going through Edwin at all. You would ordinarily use this command only for fully debugged code that you don’t want to see, just to load into Scheme.

1.1.6 Text and graphics

Each Chipmunk computer actually has two logically distinct screens that share the same physical monitor—a text screen and a graphics screen. Normally, only text will appear on the monitor. If you run a Scheme program which draws pictures, you may need to press graphics in order to see the image. Pressing graphics makes the graphics appear if it is not visible; pressing graphics again, hides the text screen so that only the graphics is showing. The alpha key works similarly, showing text and making the graphics invisible.

Text and graphics are also printed in different ways. To print text, you use an Edwin command that creates a listing on the central printer that your Chipmunk shares with the others in its group. Unfortunately, these printers do not print graphics. To print a picture, you need to run a Scheme command that saves the picture on your disk as a “picture file”. Then you need to take your disk to one of the special Chipmunks that has a graphics printer attached, and issue another Scheme command that loads the graphics file and prints you picture. See section 1.2.6 below for more information.

1.1.7 Summary

Figure 1.1 shows a summary of the parts of the system described above, with indications of how information flows between the various pieces.

1.2 Using the Chipmunks

The Chipmunks are left powered on at all times, because they can be damaged by being turned on and off frequently. Please don’t touch the power switch (it’s the button on the right, underneath the front of the keyboard). Chipmunks which are not being used display a picture or a welcome message.

1.2.1 Logging In

When you have found a Chipmunk no one else is using, insert your disk into either floppy disk drive, through one of the slots just above the keyboard. Lift the latch to open the drive, and insert the disk, label upwards and closest to you. Close the drive door by pulling the latch down from the top of the drive until it snaps into position. If the Chipmunk is showing a picture, press space to see the welcome message. When the welcome message appears on the screen, follow the directions, and the Chipmunk will present you with the *scheme* buffer in Edwin, running Scheme. (Read chapter 2 for an explanation.) You are now logged in to the Chipmunk.

If you are sure a Chipmunk is not being used, but it is not showing the login screen (either a picture or the welcome message), you should logout and login anew before using the system, to make sure that it is completely restored to its fresh state. This prevents any mistakes made by the previous user from affecting your work.

1.2.2 Directories and Files

A file is a bunch of text (English text, Scheme programs, etc.) that is stored together on a disk. Each file has a name which must be unique on the disk.

1.2. USING THE CHIPMUNKS 7

Figure 1.1: The elements of the Chipmunk universe.

Here are some typical file names:

NOTES.TXT    PROBSET1.SCM    ALPHA.SCM

The three letters at the end of the name specify, by convention, the type of information contained in the file. Files containing Scheme programs have names ending with .scm, and filenames of normal text files end with .txt. Filenames cannot be longer than sixteen characters.

The list of all the files on the disk is called a directory, and Edwin contains commands that enable you to view the directory.

In addition, every disk has a volume name, which identifies it as a group of files. If you are using two disks at the same time (one in each drive) you use the volume names to distinguish between them.

To refer to a file, specify it by its volume name followed by its filename;

e.g., MYDISK:PROBSET1.SCM or BACKUP:NOTES.TXT. If the disk containing the

file is the one you logged in with, the volume name prefix is not required.

1.2.3 Initializing the Floppy Disk

Before a floppy disk is first used, it must be initialized. During this process, the Chipmunk places information on the floppy which will enable it to find your work later on. Initialization happens automatically when you log in with an uninitialized disk; the Chipmunk detects the uninitialized disk and displays a message asking you whether to initialize it. Initializing a disk will erase everything on it, so don’t let the Chipmunk initialize a disk if you think it contains something you want to keep. In any case, follow the directions on the screen.

When the Chipmunk initializes a disk, it asks you for a name for the disk (a volume name). Give a short name of the form “mydisk:” (don’t forget the colon ‘:’). Initializing takes a few minutes, but you only have to do it once for each disk you use. After disk initialization, logging in proceeds as normal (see above).

1.2.4 Loading Problem Sets

All the files you will need to complete a problem set are available on the Chipmunk. To load the files for a particular problem set into the Chipmunk, use the Edwin extended command Load Problem Set; press extend ( k_{2} ), then type load problem set and press enter . Edwin will ask for the problem set number of the problem set you want; respond by typing the number, then pressing enter .

If there are no copies of the problem set files on your disks already, Edwin copies the ones you may want to change onto your floppy disk. If there are already copies on your disk, but they are different from the originals, Edwin asks whether you want to keep your changed files, or erase them and start over from the originals. Follow the instructions on the screen carefully.

In any case, once Load Problem Set is finished, a full set of files for the problem set will be on your floppy disk, and Edwin will have loaded all the appropriate files for you to examine and modify.

1.2.5 Saving Your Work

Be sure to save your work on your floppy disk before leaving the lab, because your work is automatically erased from the computer when you log out.

Two different keys can be used for saving buffers in Edwin: save file ( k_{0} ) and write file ( ctrl – shift – k_{0} ). The save file key saves the current buffer to the file from which it was originally loaded. The write file key always asks you what filename to use. If you want to save an extra copy of a file, use this key. (See section 2.18.)

When you save a file on your floppy disk for the second time, Edwin erases the original copy of the file and replaces it with the new version. However, it asks you for permission first:

   File 'MYDISK:PS2-ANS.SCM' exists.  Write anyway (Yes or No)?

Answer ‘yes’ if you are sure you want to replace the old version with the new work you have done, and ‘no’ otherwise.

Save your work on disk regularly as you work on problem sets. If there is a power outage or computer problem (they don’t happen often, but they do happen), the more recently you’ve saved your work, the better.

1.2.6 Printing text and pictures

There are several special keys for making printed text listings of your work on the text printers. Type print buffer ( shift – ins ln ) to print the contents of the entire buffer in which you are currently working. (Section 2.20 describes other commands for printing portions of your work.) ^{1}

You cannot use the text printers to make hardcopies of pictures drawn on the graphics screen. Instead you must use one of the small inkjet printers that are attached to several of the Chipmunks throughout the lab.

To get hardcopy of an image on your graphics screen, you must first save the image as a “picture file” on your floppy disk. Give the Scheme command store-picture, which requires a file name as input, for example,

(store-picture "monalisa.pic")

Later, log in (using your disk) at one of the Chipmunks with an inkjet printer, and use the Scheme print-picture-file command, for example,

(print-picture-file "monalisa.pic")

Do not use print-picture-file on a Chipmunk that does not have a graphics printer attached—it will wedge the computer and may cause you to lose your work.

If you would like to redisplay on the screen an image that you have presiously saved in a picture file, you can use the load-picture command. (This does not require a graphics printer.)

1.2.7 Logging Out

When you are finished using the Chipmunk, be sure to log out using the Edwin extended command Logout. Press extend , then type Logout and press enter . Edwin will find out whether all buffers have been saved on floppy disk since you changed them, and ask you if you want to save any that might need saving.

When the picture or welcome message appears on the screen, you are logged out. Don’t forget to take your floppy disk with you.

1If you would like to force a page break somewhere in your paper listing, you must insert a #\Page character into the buffer you’re printing; the #\Page character will appear as ^L in the file. To insert the character, type shift – ins chr , then ctrl – l ; the ^L will appear at the current cursor position. When you print the buffer, the printer will insert a page break where the #\Page character appears, and the ^L will be invisible.

1.3 Chipmunk Status Indicators

The Chipmunk always displays the time (with a flashing colon ‘:’ between the hours and minutes) and a status character in the bottom, right-hand corner of the screen. There are several possible status characters:

IO The Chipmunk is ready for you to type something.

G The Chipmunk is garbage-collecting (cleaning up its memory). Please wait for it to finish.^{2}

π The Chipmunk is running some Scheme code, and is not waiting for you to type anything. If you want it to stop, press abort (see section 2.4).

1.4 Crashes

The Chipmunk should always be running Edwin. However, if something goes wrong with the Chipmunk software, it is possible that the system will “crash” while you are using it (see the Cynic’s First Law, chapter 3). If you cannot get Edwin to respond to anything you type, or if a strange program suddenly takes over the machine, then Edwin or Scheme may have crashed. If this happens, ask a lab TA for help.

If your Chipmunk crashes, and there are no TAs in the lab, you can try to fix the Chipmunk by pressing shift and reset together, then typing “sb” (while holding shift down to make it lower-case), and finally pressing enter . This will “reboot” the Chipmunk, completely clearing its memory, starting it as if it had just been turned on (remember, never turn a Chipmunk off). Only reboot the Chipmunk when it is hopelessly screwed up, because you will lose all work you haven’t yet saved on your disk. Rebooting takes about five minutes. Please do not do this when there are TAs available to help you.

2Edwin is written in Scheme. Like most Lisp-style languages, Scheme must occassionally stop to garbage collect. (See section 5.3 of the 6.001 text for information about garbage collection.) If Edwin suddenly seems to “die,” don’t panic; it may just be garbagecollecting.

1.5 Backing up your disks

Every experienced programmer has lost files at one time or another. You will, too. Files get accidentally overwritten, fuses blow just when the computer is writing to the disk, armed bandits run through the computer lab ripping your disks out of the Chipmunks and spiriting them away; disks get lost, demagnetized, folded, eaten by your roommate in a fit of exuberance; etc., etc.

Losing files is part of life, like catching a cold, paying taxes, or having to suffer through overly long problem sets.

Every experienced programmer who is not stupid has learned to back up his or her files. Even this will not protect you against a malevolent universe, but it helps.^{3}

Please make periodic backups of your work. The Scheme command backup-floppy will copy the contents of one floppy disk to another. When you use this command, follow the instructions carefully. In particular, don’t confuse the disk that you are backing up from with the disk that you are backing up to. In this veil of tears, there is nothing more tragic than an programmer who has inadvertantly destroyed a disk by attempting to make a backup of it.

3Indeed, there are some who believe that making backups simply causes the Universe to go to even further extremes to foil you. Tom Knight remarks that he is careful never to keep all backup copies of important files on only one coast of the United States.

Edwin, the Editor

Edwin is the computer program used for typing, editing, and testing Scheme programs on the Chipmunks. It is based on Emacs, another text editor, originally designed and implemented in the 1970s by Richard M. Stallman at MIT. Edwin works almost exactly like GNU Emacs, the version of Emacs used on Project Athena computers. Unlike Emacs, however, Edwin is written in Scheme.

Edwin is a sophisticated text editing program. This manual gives only a basic introduction, but it explains everything you need to know about Edwin to do 6.001 problem sets. Read through it once carefully before you try to use the Chipmunks; use it as a reference manual thereafter.

2.1 Buffers and Windows

Use Edwin to work with as many separate chunks of text as you wish; each chunk is kept in a buffer. The text in a buffer may be a Scheme program, English prose, a list of files, or anything else that you can type on the keyboard.

Most buffers hold text you have loaded in from a file on disk, or text you have typed but not yet saved as a file. All buffers are erased as soon as you log out, so you should make sure to save all buffers containing your work to files on your floppy disk first. The next time you use the Chipmunks, just load your files from disk and you will be ready to continue working on them.

Some buffers are not used to edit files. The *scheme* buffer, for example, is where you carry out all “conversations” with Scheme; in other words, this is where you test Scheme programs you have written or changed.

Each buffer has one major mode, and maybe some minor modes. Major modes determine special Edwin behavior particular to the language you are using in the buffer (e.g., Scheme or English). Minor modes add special features regardless of the language you are using in the buffer.

Edwin can display several buffers on the screen at once, each in a separate window. A window is a rectangular area of the screen set aside to display all or part of a particular buffer. Not every buffer will always be visible at the same time; usually, there are one or two windows, but three or more buffers.

2.2 The Edwin Screen

The Edwin screen is divided into three types of rectangular areas. They are:

Typein Window The last line on the screen is the typein window. Whenever Edwin needs to ask you a question, it shows the question in the typein window.

Edit Windows Each area of white-on-black text above the typein window is an edit window. Each Edit Window displays all or part of a buffer, for you to read or edit.

Mode Lines The black-on-white line of text at the bottom of each edit window is a mode line. Each mode line shows its buffer’s name (usually the same as the file name), major and minor modes, and other information.

Whenever Edwin is ready for you to type something, it displays the cursor, a blinking underline, to show you where your typing will appear on the screen. If you type an ordinary character (letter, number, or punctuation), it is inserted at the current cursor position and the cursor moves past it. If you type when the cursor appears in an Edit Window, your typing is inserted into the corresponding buffer.

The point is an invisible marker between two adjacent characters in each buffer. The cursor always reflects the position of the point in the current buffer; the point is between the character just left of the cursor and the character above the cursor. For example, if the screen shows:

   The point is in this wo\underline{r}d. ,

then the point is between the ‘o’ and the ‘r’ in “word.”

Each mode line looks something like this:

-----Edwin: STUDENT.SCM            (Scheme)--57%--------------

This mode line, for example, gives the name of the buffer, STUDENT.SCM; that the buffer is configured in Scheme mode; and that the part of the buffer visible on the screen is fifty-seven percent of the way through the whole buffer. Saying that the buffer is in Scheme mode means that, in addition to ordinary Edwin features, there are special features to aid you in using Scheme.

A mode line that contains two asterisks ** at the left, such as

--**-Edwin: STUDENT.SCM            (Scheme)--57%--------------

indicates that the buffer has been changed since the last time it was saved on disk.

Certain buffers used by the system, such as buffers used for displaying messages and lists of files, are read-only. Edwin indicates this by two percent signs %%. For example, the mode line

--%%-Edwin: BEN:                    (Dired)--Top--------------

indicates that the BEN: buffer is read-only—Edwin will not let you change the contents of that buffer. In addition, the word Top indicates that the top (beginning) of the buffer is visible in the window, and Dired indicates that the buffer is in “directory edit” mode (see section 2.19).

For a window in which you can type directly to Scheme (e.g., the *scheme* buffer), the mode line looks like this:

--**-Edwin: *scheme*          (Interaction)--All--------------

The word Interaction means that the buffer is connected directly with Scheme. When you press execute in this buffer, Edwin will send Scheme the expression before the cursor, and Scheme’s result will be printed in the buffer.

2.3 Commands

Edwin acts very much like a typewriter when you type normal keys, like letters, numbers, and punctuation. However, to get Edwin to do anything special, such as loading files, running a Scheme program, or switching to another buffer, you must use special keys, like ctrl and the grey keys across the top of the keyboard. These keys issue commands to Edwin, telling it what you want it to do.

There are two types of Edwin commands: commands available directly on the special keys, and extended commands. Extended commands are used by pressing extend ( k_{2} ), followed by the name of the command. All commands are available this way, but the special keys are more convenient. In fact, you will probably need to use only two extended comands: load

problem set and logout.

There are key diagrams mounted on the Chipmunk around the grey keys and the floppy disk drives. To use a command on one of these special keys, hold down some combination of shift and ctrl (as indicated on the diagrams), while pressing the special key.

When reading tables like the one below, remember that a hyphen “-” between keys means that you should hold them down simultaneously. For example, ctrl – ← means “hold ctrl down while pressing ← .” On the other hand, extend load problem set means “press and release extend , then type ‘load problem set’ and press enter .”

If you are familiar with Emacs, you will find that almost all of the Edwin commands can be typed in the way they normally would be in Emacs, as well as with the special keys at the top of the Chipmunk keyboard. For example, the abort command can be typed either by pressing the abort key (which is key k_{2} ), or by typing ctrl –G, as in ordinary Emacs. The tables below list both versions of the command. Use whichever one you find most comfortable. Emacs “escape” commands are typed with the aid of the run key at the right of the keyboard. For instance, to type what in Emacs would be “escape-W”, you type run followed by w . (Do not press both keys simultaneously, as you would with ctrl .)

Here are the special keys necessary for using Edwin commands:

Extended Command  extend ( k_{2} )

run x (Note: run is labeled esc on most computer keyboards.)

Begin an extended command. To use an extended command, press this key, then type the name of the command. Finish by pressing enter .

ABORT  abort ( k_{1} )

ctrl – g

Stop whatever operation Edwin is performing, or cancel a command you’ve already started typing.

Universal Argument  argument ( k_{8} )

ctrl – u

Preceding any command (regular or extended), this key tells Edwin that you wish to give the command an argument.

2.3.1 Arguments Optional

An argument to an Edwin command is analogous to a parameter in a Scheme procedure. However, arguments to Edwin commands are always optional; if no argument is given, a default argument is automatically supplied to the command.

Many Edwin commands accept optional numeric arguments, assuming an argument of one if none is given. Pressing argument first gives these commands an argument of four. For example, pressing ↓ once moves the cursor down one line; typing argument ↓ moves the cursor down four lines. If you type argument several times successively, Edwin will multiply the argument by four each time, so typing argument argument argument ↓ will move the cursor down sixty-four (4 × 4 × 4) lines. Typing a number after argument makes that number the argument; typing argument 123 ↓ will move the cursor down 123 lines.

Some Edwin commands take optional character string arguments, so prefixing them with argument will cause them to ask for a string argument.

If you are unsure about whether a command takes an argument, or what it means for that command to take an argument, use the Edwin help function “Describe Function” by pressing help ( shift – k_{2} ). (See section 2.5.)

2.3.2 Extended Commands

To use an extended command, press the extend key ( k_{2} ) followed by the name of the command. Your typing will appear at the bottom of the screen, in the typein window.

You can abbreviate the command name as you type. If you press the space key while you’re typing the command name, Edwin will look for all commands whose names begin with what you’ve typed. If there is a matching command, Edwin will complete the word you are typing. If there is more than one matching command, Edwin will beep; press ? , and Edwin will list all the matching commands, then wait for you to finish typing the name of the command you want. If there is no matching command, Edwin will beep, then wait for you to correct your mistake with the back space key.

When you’ve typed the full command name, press enter ; Edwin will run your command.

2.4 Trouble

Because there are so many things you can do with Edwin, it is likely that you will make a mistake using it once in a while — yes, even you!

To stop whatever Edwin is doing, or to cancel a command before you’ve completely typed it, press the grey abort key. Pressing abort is like screaming, “Stop!” at Edwin.

In fact, abort is also useful for stopping Scheme programs other than Edwin. For example, if you start (factorial 10000), but decide that it will take too long to compute, typing abort will stop factorial and prepare Edwin to accept another command.

20 CHAPTER 2. EDWIN, THE EDITOR

2.5 Getting Help

If you’re ever confused about how to get Edwin to do something, or just want to find out more about what it can do, press help ( shift – k_{2} ) followed by one of these letters:

A Apropos.

Type a word or words that describe what you want to do, and Edwin will list all commands whose descriptions mention the words you give.

C Describe Key Briefly.

Type a key (or sequence of keys), and Edwin will give a brief description of what the key does.

D Describe Command.

Type the name of a command (usually an extended command), and Edwin will tell you what the command does and how to use it.

I Info, the documentation reader.

Info gives information on a variety of topics, among them Edwin. For help on using Info, press ‘h’ once you’ve started Info.

K Describe Key.

Type a key (or sequence of keys), and Edwin will give a complete description of what the key does.

L Show Lossage.

Shows the last one hundred characters you typed.

M Describe Mode.

Shows documentation for the current major mode, including commands peculiar to it.

T Help with Tutorial.

Starts the Emacs learn-by-doing tutorial. Edwin is sufficiently similar to Emacs that this tutorial may be useful to you.

V Describe Variable.

Type an Edwin variable name^{1}, and Edwin will describe the purpose and use of the variable.

W Where Is.

Type a command name (usually an extended command), and Edwin will tell you what key (or key sequence) you can use to run the command. All Edwin commands have names, but not all are attached to keys, so Edwin may tell you that the command “... is not on any keys.” In that case, the only way to use the command is by invoking it as an extended command (using the extend key).

1This is good only for Edwin variables. It is not useful for finding information on Scheme variables.

2.6 Typing

Before you start typing, make sure you’re “in” the buffer you want to change. If the buffer you want to change is in one of the windows on the screen, and the cursor is in that buffer, then go ahead and type. Otherwise, press the grey select buffer key ( k_{4} ). Edwin will ask you which buffer to use; type its name (press ? for a list of buffers) followed by enter . Edwin will display the buffer you’ve requested in a window, placing the cursor in that window; you are now “in” the right buffer. Now, you are ready to type.

To insert text into the buffer, just type. Edwin will insert characters wherever the cursor appears. Whatever you type is inserted just before the cursor. When you get to the end of a line, press the enter key, just as you would on a normal typewriter, to get to the beginning of the next line.

When you get to the bottom of the screen, Edwin automatically gives you more space to work with.

Correct typing mistakes by pressing the back space key, just like on a correcting typewriter.

tab

Indent the line.

ctrl – j

Insert a blank line before the point.

ctrl – o

Insert a blank line after the point.

ctrl – x = ctrl – q

Indent for Tab  tab Newline  enter Open Line  ins ln What Cursor Position  shift – k_{9} Display the current cursor position in the typein window.

Quoted Insert  shift – ins chr Insert a special character at the current point, then move the point forward.

2.7 Moving through a Buffer

Use the arrow keys to move the cursor around in a buffer. For the most part, the arrow keys do exactly what you would expect:

Up Real Line  ↑

ctrl – p

Move the cursor up one line. Stay at the same horizontal position, if possible.

Down Real Line  ↓

ctrl – n

Move the cursor down one line. Stay at the same horizontal position, if possible.

Backward Character  ←

ctrl – b

Move the cursor left one character. If at the start of a line, move to the end of previous line.

Forward Character  →

ctrl – f

Move the cursor right one character. If at the end of a line, move to the start of the next line.

Backward Word  shift – ←
run b

Move backward to the beginning of the previous word.

Forward Word  shift – →
run f

Move forward to the end of the next word.

Beginning of Line  ctrl – ←

ctrl – a

Move the cursor to the beginning of the line.

End of Line  ctrl – →

ctrl – e

Move the cursor to the end of the line.

2.7. MOVING THROUGH A BUFFER 23

Previous Screen  ctrl – ↑
run v

Scroll the text in the buffer downward to reveal the previous window-full of text.

Next Screen  ctrl – ↓

ctrl – v

Scroll the text in the buffer upward to reveal the next window-full of text.

Goto Beginning  ctrl – shift – ↑
run �

Move to beginning of buffer.

Goto End  ctrl – shift – ↓
run �

Move to end of buffer.

2.8 Correcting Simple Mistakes

Use the following keys to correct simple mistakes:

Backward Delete Hacking Tabs  back space

back space

Delete the character before the point, treating TAB characters as several SPACE characters. If the point is at the beginning of a line, join the line to the end of the previous line.

Delete Character  del chr

ctrl – d

Delete the character after the point. If the point is at the end of a line, join the next line to the end of the current line.

Backward Delete Character  ctrl – del chr

Delete the character before the point, treating TAB characters as single units. If the point is at the beginning of a line, join the line to the end of the previous line.

Kill Word  shift – clr→end
run d

Kill characters forward from the point to the end of the nearest word.

Backward Kill Word  ctrl – shift – del chr
run back space

Kill characters backward from the point to the beginning of the nearest word.

Kill Line  clr→end

ctrl – k

Kill the characters following the point on the current line.

Transpose Characters  k_{3}

ctrl – t

Interchange the two characters around the point. If the point is at the end of the line, interchange the two characters preceding the point.

Transpose Words  shift – k_{3}
run t

Interchange the words around the point.

2.9 Undo

Edwin’s undo feature is useful for correcting bigger mistakes, like accidentally erasing an entire Scheme procedure, or inserting one paragraph in the middle of another. Edwin records all changes you have made to a buffer since the last time you saved the buffer, up to a certain limit (several thousand characters’ worth). Use the undo key ( ctrl – clr→end ) to undo the last change you made to the current buffer. If you press undo several times in a row, Edwin will undo earlier and earlier changes. Each time you press undo , Edwin will move the point to the next-most-recent change, and undo it.

Sometimes, you may accidentally undo more changes then you want to. When this happens, issue some command that will not change the buffer (like ← ), then press undo to redo what you accidentally undid.^{2}

If you undo all the changes you made to the buffer since you last saved it, further undoing will have no effect. When all changes have been undone, the two asterisks (**) on the left side of the buffer’s mode line will disappear. At this point, the buffer is exactly the same as it was the last time you saved it.

2How many undos would an undo undo if an undo could undo undos?

2.10 The Region

Each buffer has a point, a mark, and a region.

The cursor is just a reflection of the point, an invisible marker between the character before the cursor and the character above the cursor in each buffer. Wherever the point moves, the cursor follows.

The mark is another invisible place marker in the buffer. Most commands which move the point any distance set the mark to the point before they move it. To set the mark manually, press k_{9} ; the mark will be at the same position as the point.

The region is the text between the point and the mark. Many commands operate on the region. The most common use for the region is moving blocks of text from one place in the buffer to another place, or to another buffer. Section 2.11 describes the most important commands for dealing with regions.

To create a region, place the cursor at one end of the text and press k_{9} , then move the cursor to the other end of the text. The text between the point and the mark is now considered the region. Remember that if you move the point (the cursor in that buffer), you change what is considered to be the region.

Set/Pop Mark  set mark ( k_{9} )

ctrl – shift – @

Set the mark at the current point. When you need to mark off a region of text, use this command to mark the beginning of the region, and move the point (cursor) to the other end of the region.

Exchange Point and Mark  ctrl – k_{9}

ctrl – x ctrl – x

Exchange point and mark; switch the positions of the point and the mark. This is useful for moving back and forth between two locations in a buffer. It is also useful for finding the mark’s exact location in the buffer.

Mark Whole Buffer  ctrl – shift – k_{9}

ctrl – x h

Mark the whole buffer as the region. Put the point at the beginning of the buffer, and the mark at the end of the buffer.

2.11 Kills and Yanks

Most commands which erase text from the buffer save it in an invisible place called the kill ring, so that you can copy the text, move it, or get it back if you decide not to erase it. Edwin holds the last several blocks of text saved or killed in any buffer in the kill ring.

To get the most recently saved^{3} or killed text back from the kill ring, place the point where you would like the text to appear, then do a yank by pressing recall ; Edwin will insert the text from the kill ring just before the point. To get the next-most-recently saved or killed text, press ctrl – recall ; Edwin will replace the yanked text with the next-most-recently saved or killed text. Continue pressing ctrl – recall until the text you desire appears.

Kill Region  ctrl – shift – del ln

ctrl – w

Kill the region and save it in the kill ring.

Copy Region  ctrl – shift – recall
run w

Save the region in the kill ring.

Un-Kill  recall

ctrl – y

Insert the just-killed text at the point (yank the text from the kill ring.)

Un-Kill Pop  ctrl – recall
run y

Replace the just-yanked text with the text saved or killed just before it.

3Here, “saved” does not mean “saved to disk;” it only means “stored away for future use.”

2.12 Editing Scheme Programs

Edwin has two major modes with special commands for editing Scheme programs: Scheme mode and Interaction mode. Editing Scheme programs is done in Scheme-mode buffers, and interacting directly with Scheme (i.e., running your programs) is done in an Interaction-mode buffer (usually labeled *scheme*). The essential difference is that Scheme’s output is placed in the interaction buffer. Here are the special commands for editing Scheme available in both Scheme-mode and Interaction-mode buffers:

Forward Sexp  ctrl – shift – →

Move point forward across one balanced Scheme expression.

Backward Sexp  ctrl – shift – ←

Move point backward across one balanced Scheme expression.

Beginning of Definition  shift – ↑

Move point backward to previous beginning of a Scheme definition.

End of Definition  shift – ↓

Move point forward to next beginning of a Scheme definition.

Kill Sexp  ctrl – shift – clr→end

Kill the next Scheme expression after the point.

Indent Sexp  ctrl – k_{2}

Indent each line of the Scheme expression starting just after the point.

Indent for Comment  ins chr
run ;

Indent this line’s comment to the comment column, or insert an empty comment.

2.12. EDITING SCHEME PROGRAMS 29

Set Comment Column  ctrl – ins chr

ctrl – x ;

Set the comment column to be the current horizontal position of the point. If preceded by a numeric argument (see section 2.3), set comment column at the column given by the argument. Comments inserted using ins chr will appear at this horizontal position.

Delete Horizontal Space  ctrl – shift – k_{3}
run \

Delete all spaces and TABs around the point, on the current line.

Transpose Sexps  ctrl – k_{3}

Interchange the Scheme expressions around the point.

2.13 Scheme Interaction

Before you can run a Scheme program you have typed in a Scheme-mode buffer, you must send it to Scheme by evaluating it. Every time you change your program, you must be sure to evaluate all the parts which have changed, so that the Scheme will know about them.

The Interaction-mode buffer is used for working directly with Scheme. Whenever Scheme is ready for you to type something, it displays a prompt on the left side of the last line in the Edwin Interaction-mode buffer:

 ==> _

At this point, anything you type will be taken by Edwin and sent to Scheme, as soon as you press execute . Scheme will accept what you typed as a Scheme expression, evaluate it, and display the result on the lines below. Below the result, Scheme will display another prompt, signalling that it is ready for you to type another Scheme expression. For example,

 ==> (factorial 10)
3628800
 ==> _

Here are the special commands for evaluating Scheme expressions and definitions, available in both Scheme-mode and Interaction-mode buffers:

6.001 Evaluate Expression  execute

Evaluate the expression preceding the point.

6.001 Evaluate Definition  ctrl – k_{7}

Evaluate the definition containing the point.

Evaluate Region  ctrl – shift – k_{7}

Evaluate the region.

2.13. SCHEME INTERACTION 31

6.001 Evaluate Buffer  shift – k_{7}
run o

Evaluate the entire buffer.

Scheme Interaction Buffer  scheme ( k_{7} )

Place the Interaction-mode buffer (usually *scheme*) in the current window. If there is no Interaction-mode buffer, create one and put it in the current window.

2.14 Search

Edwin has commands Incremental Search and Reverse Search for search-

ing through a buffer for occurrences of a particular pattern of text.

To search forwards from the point, press k_{5} ; to search backwards from the point, press ctrl – k_{5} . Next, type the text you seek; your typing will appear in the typein window. As you type, Edwin will move the point forward to the next occurrence of the text you have typed so far (the next match). If Edwin cannot find the text, it will display ‘Failing I-Search’ or ‘Failing Reverse I-Search’ at the left side of the typein window, depending on the direction of the search.

Correct the search text you are typing with back space . As you press this key, Edwin may move the point back to a previous match, because it always looks for the first match after the point (or before the point, in reverse search).

To search for the first match after the one at the point, press k_{5} or ctrl – k_{5} again. To change the direction of search, press k_{5} for forward or ctrl – k_{5} for backward.

If you press k_{5} when a forward search has failed, Edwin will “wrap around” the buffer, starting the search over at the beginning of the buffer. If you press ctrl – k_{5} when a reverse search has failed, Edwin will start the search over at the end of the buffer.

When you find the text you are looking for, press run . This will stop the search, leaving the point immediately after the matching text.

If you press abort during a search, Edwin will return the point to the position where the search began, stopping the search. You must press abort twice to end a failing search. The first time you press abort , Edwin will move you to the previous match; the second time, Edwin will cancel the search entirely, returning to the position where the search began.

Incremental Search  k_{5}

ctrl – s

Search forward incrementally.

Reverse Search  shift – k_{5}

ctrl – r

Search backward incrementally.

2.15 Replace

Not only can Edwin search a buffer for a particular pattern of text, it can replace some or all instances of this text with another piece of text. Replace String replaces all instances of the search text with the replacement text; Query Replace finds instances of the search text, stopping at each match to ask you whether to replace it with the replacement text.

Replace String  ctrl – shift – k_{5}

Ask for two pieces of text. Search through the buffer, beginning at the point, looking for occurrences of the first piece of text. Wherever it’s found, replace it with the second piece of text.

Query Replace  ctrl – k_{5}
run %

Ask for two pieces of text. Search through the buffer, beginning at the point, looking for occurrences of the first piece of text. Wherever Edwin finds a match, ask whether to replace it with the second piece of text.

To use Replace String, press ctrl – shift – k_{5} . First, Edwin will ask you to type the search text in the typein window; press enter when you have. Next, Edwin will ask you to type the replacement text in the typein window; again, press enter when you have. Then, Edwin will search forward from the point, replacing all instances of the search text with the replacement text.

Be careful with Replace String, because it can change your buffer in unexpected ways — it will do what you tell it to, not necessarily what you want it to do. It is a good idea to save your buffer to disk before using this command.

Start Query Replace exactly as you would Replace String, supplying search text and replacment text. Edwin will stop at each match following the point, asking you whether to replace it. The following responses are possible:

space  Replace this match, then search for the next.
back space  Search for the next match without replacing this one.
run  Stop the search, leaving the point at the latest match.
·  Replace this match and stop the search.
!  Replace all remaining matches with no more questions.
∧  Move the point back to the previous match.

2.16. BUFFERS 35

2.16 Buffers

Use these commands to control Edwin’s buffers:

Select Buffer  select buffer ( k_{4} )

ctrl – x b

Ask for the name of another buffer, and place that buffer in the current window. Edwin will suggest one buffer; accept the suggestion by pressing enter , or type the name of the one you really want to see instead.

Twiddle buffers  ctrl – k_{4}

Select the “other” buffer. Same as typing Select Buffer Enter .

Kill Buffer  ctrl – shift – k_{4}

ctrl – x k

Kill the current buffer; completely eliminate the current buffer and all the text in it.

List Buffers  shift – k_{4}

ctrl – x ctrl – b

List all the existing buffers in a new buffer called *Buffer-List*.

The following keys have special functions in a *Buffer-List* buffer (created by the List Buffers command, above):

m  Mark buffer on current line to be displayed.
q  Select buffer on current line.
1  Select buffer on current line in a full-screen window.

2 Select buffer on current line in one window, and the buffer selected before it in another window.

s Mark the buffer on the current line as a buffer to be saved when you press x in the *Buffer-List* buffer.

d Mark the buffer on the current line to be killed when you press x

               in the *Buffer-List* buffer.

x  Kill or save the buffers previously marked with s and d .
u  Remove all ‘kill’ and ‘save’ marks from the current line.
back space  Move up one line and remove marks.
space  Move down one line.

2.17. WINDOWS 37

2.17 Windows

Use these commands to control the appearance of windows on the screen:

Other Window  other window ( k_{6} )

ctrl – x o

Move the cursor to the window immediately below the current window, or to the top window if the cursor is already in the lowest window.

Split Window Vertically  two windows ( shift – k_{6} )

ctrl – x 2

Split the current window into two windows.

Delete Other Windows  one window ( ctrl – k_{6} )

ctrl – x 1

Expand the current window to fill the entire screen.

Enlarge Window Vertically  grow window ( ctrl – shift – k_{6} )

ctrl – x ∧

Make the current window one line bigger. If an argument is given, make the current window that number of lines bigger.

New Window  shift – recall

ctrl – l

Center the point in the window and redisplay the screen.

2.18 Saving and Loading Files

Use these commands to save and load files:

Find File  find file ( shift – k_{0} )

ctrl – x ctrl – f

Load a file into a new Edwin buffer. Edwin will ask you the name of the file to load.

Find Alternate File  visit file ( ctrl – k_{0} )

ctrl – x ctrl – v

Kill the current buffer, then load another file into a new buffer in the current window. Same as typing ctrl – shift – k_{4} enter find file . Edwin will ask the name of the file to load.

Save File  save file ( k_{0} )

ctrl – x ctrl – s

Save current buffer to its file. If there is not yet a file associated with the buffer, Edwin will ask for one in the typein window.

Write File  write file ( ctrl – shift – k_{0} )

ctrl – x ctrl – w

Save current buffer to a file. Edwin will ask the name of the file to which to save this buffer. Normally, you will want to use save file ; use write file when you want to make extra disk copies of a buffer.

Insert File  extend Insert File

ctrl – x i

Insert the contents of a file into the buffer at the current point. Edwin will ask you the name of the file to insert.

2.19 Directory Edit

Edwin has a major mode, Dired, for dealing with directories of files on disks. To create a Dired-mode buffer for a disk directory (for example, for one of your floppy disks), issue the extended command dired (i.e., type extend dired enter ). Edwin will ask, in the typein window, for the name of the directory to list. Enter your response, remembering to end the disk name with a colon ‘:’, and press enter . If Edwin can find the directory you give, it will list the files. You can move through the list of files with the normal cursor motion commands (arrow keys, etc.). The following keys have special functions in Dired-mode buffers:

f  Load the file on the current line into a new Edwin buffer.

d Mark the file on the current line, so that it will be erased when you press x in the buffer.

u Remove marks (made by d ) from the current line, so that the file on the current line will not be deleted when you press x .

Leave the Dired buffer, erasing the files previously marked using d .

back space  Move up one line and remove marks.

space  Move down one line.

x  Erase the files previously marked using d .

q

40 CHAPTER 2. EDWIN, THE EDITOR

2.20 Printing

Use these commands to print your work on paper:

Print Buffer  shift – ins ln

Print the entire buffer. Print Region ctrl – ins ln Print the region. Print File ctrl – shift – ins ln Print a file. Edwin will ask you the name of the file to print.

2.21 Miscellaneous Commands

Here are some commands which do not fit in the categories above:

Uppercase Initial  ctrl – k_{8}
run c

Capitalize the first full word following the point. Uppercase Word shift – k_{8}

run u

Convert the first full word following the point to all upper case letters. Lowercase Word ctrl – shift – k_{8}

run l

Convert the first full word following the point to all lower case letters. Screen Video ctrl – shift – ins chr

ctrl – x v

Reverse video. Change white-on-black text to black-on-white and vice versa. This only affects how Edwin displays text on the screen, not how it will be printed.

Debugging

Even computer software that has been planned carefully and written well may not always work correctly. Mysterious creatures called bugs may creep in and wreak havoc, leaving the programmer to clean up the mess. Some have theorized that a program fails only because its author made a mistake, but experienced computer programmers know that bugs are always to blame. This is why the task of fixing broken computer software is called debugging.

It is impossible to prove the correctness of any non-trivial program; hence the Cynic’s First Law of Debugging:

Programs don’t become more reliable as they are debugged; the bugs just get harder to find.

Scheme is equipped with a full complement of special software for finding and removing bugs. The debugging tools include facilities for tracing a program’s use of specified procedures, for examining Scheme environments, and for setting breakpoints, places where the program will pause for inspection.

Many bugs are detected when programs try to do something which is impossible, like adding a number to a symbol, or using a variable which does not exist; this type of mistake is called an error. Whenever an error occurs, Edwin automatically describes the error in the Typein Window and asks whether to start the debugging tools. For example, using a nonexistent variable foo will cause Edwin to respond, “Unbound Variable FOO -- Debug?” Typing y will start the debugging tools; n will return to Edwin.

Sometimes, a bug will never cause an error, but will still cause the program to operate incorrectly. For instance,

    (prime? 7)  ⟹ #f

In this situation, Scheme does not know that the program is misbehaving. The programmer must notice the problem and, if necessary, start the debugging tools manually.

There are several approaches to finding bugs in a Scheme program:

• Inspect the original Scheme program.

• Use the debugging tools described below to follow your program’s progress.

• Edit the program to insert checks and breakpoints.

Only experience can teach how to debug programs, so be sure to experiment with all these approaches while doing your own debugging. Planning ahead is the best way to ward off bugs, but when bugs do appear, be prepared to attack them with all the tools available. Remember that the 6.001 Lab is equipped with some of the most powerful Scheme debugging tools available – 6.001 TAs. If you really get stuck, ask a TA for help.

3.1 Subproblems and Reductions

Understanding the concepts of reduction and subproblem is essential to good use of the debugging tools. The Scheme interpreter evaluates an expression by reducing it to a simpler expression. In general, Scheme’s evaluation rules designate that evaluation proceeds from one expression to the next by either starting to work on a subexpression of the given expression, or by reducing the entire expression to a new (simpler, or reduced) form. Thus, a history of the successive forms processed during the evaluation of an expression will show a sequence of subproblems, where each subproblem may consist of a sequence of reductions.

For example, both (+ 5 6) and (+ 7 9) are subproblems of the following combination:

    (* (+ 5 6) (+ 7 9))

If (prime? n) is true, then (cons 'prime n) is a reduction for the following expression:

    (if (prime? n)
        (cons 'prime n)
        (cons 'not-prime n))

This is because the entire subproblem of the if combination can be reduced to the problem (cons 'prime n), once we know that (prime? n) is true; the (cons 'not-prime n) can be ignored, because it will never be needed. On the other hand, if (prime? n) were false, then (cons 'not-prime n) would be the reduction for the if combination.

The subproblem level is a number representing how far back in the history of the current computation a particular evaluation is. Consider factorial:

    (define (factorial n)
      (if (< n 2)
          1
          (* n (factorial (- n 1)))))

If we stop factorial in the middle of evaluating (- n 1), the (- n 1) is at subproblem level 0. Following the history of the computation “upwards,”

(factorial (- n 1)) is at subproblem level 1, and (* n (factorial (-

n 1))) is at subproblem level 2. These expressions all have reduction number 0. Continuing upwards, the if combination has reduction number 1.

Moving backwards in the history of a computation, subproblem levels and reduction numbers increase, starting from zero at the expression currently being evaluated. Reduction numbers increase until the next subproblem, where they start over at zero. The best way to get a feel for subproblem levels and reduction numbers is to experiment with the debugging tools, especially Debug.

3.2 Debug (The Continuation Browser)

Debug, otherwise known as the Continuation Browser, is the debugging tool which starts when an error occurs and you answer y to Edwin’s question, “Debug?” When Debug starts, it records all the information necessary to continue running the Scheme program which caused the error, and lets the programmer inspect this information – hence the name “Continuation Browser.”

Debug runs in the Edwin buffer *Debug, which is automatically displayed in an Edwin window when Debug starts. A typical starting Debug display looks like this:

    Subproblem Level: 0  Reduction Number: 0
    Expression:
    FOB
    within the procedure FIB
    applied to (10)

This tells us that the error occurred while trying to evaluate the expression FOB while running (FIB 10). When it starts, Debug always displays the expression which caused the error; this expression is reduction number 0 at subproblem level 0.

46 CHAPTER 3. DEBUGGING

Several keys have special functions when the cursor is in the *Debug buffer:

b  Move to the next reduction.
d  Move down to the next subproblem.

e Pop up a window (buffer *Eval* for evaluating Scheme expressions in the current environment.

f  Move to the previous reduction.
g  Move to a particular subproblem/reduction.

h Pop up a menu of subproblems to be chosen among in buffer

               *Subproblem-Menu.

p Display a pretty-printed version of the procedure which created the current environment in buffer *Procedure*.

q  Leave the Continuation Browser, killing its buffer.
u  Move up to the previous subproblem.

v Evaluate a single Scheme expression in the current environment, prompting for it in the Typein Window.

w Browse the current environment in buffer *Environment (using Where, described below).

Now, imagine that you are debugging a Scheme program to compute Fibonacci numbers. You want procedure fib to accept an integer as its single parameter, returning the corresponding Fibonacci number. But when you run (fib 10), Edwin displays the error message ``Unbound Variable FOO -- Debug?'' When you answer by pressing y , Edwin starts Debug, which displays the following:

  Subproblem Level: 0  Reduction Number: 0
  Expression:
  FOB
  within the procedure FIB
  applied to (10)

This tells you that the error occurred while trying to evaluate the expression FOB while running (FIB 10). Now suppose this error confuses you, because you don’t recognize the variable FOB – after all, you were running your Fibonacci number program, which looks like this:

    (define (fib n)
      (if (< n 2)
          1
          (+ (fib (- n 1))
     (fob (- n 2)))))

(It turns out that you made a typo, entering “fob” where you wanted “fib,” but you haven’t noticed this yet.)

You wonder what Scheme was doing (evaluating) when it encountered fob, so you press u , telling Debug to move up one subproblem level. The *Debug buffer changes to:

    Subproblem Level: 1  Reduction Number: 0
    Expression:
    (FOB (- N 2))
    within the procedure FIB
    applied to (10)

Still confused, you go up one more subproblem level by pressing u again:

    Subproblem Level: 2  Reduction Number: 0
    Expression:
    (+ (FIB (- N 1)) (FOB (- N 2)))
    within the procedure FIB
    applied to (10)

But now, you notice that this code looks suspiciously like your Fibonacci procedure. Returning to the Edwin buffer where you defined it, you see your typo, correct it, and try (FIB 10) again. Now, the Fibonacci procedure works.

In this imaginary scenario, only the u command was needed to solve the problem, but let’s try h to see a summary of evaluation history, anyway:

Sub Prb.      Procedure Name    Expression
0   0                    FIB    FOB
1   0                    FIB    (FOB (- N 2))
2   0                    FIB    (+ (FIB (- N 1)) (FOB (- N 2)))
3                               (WRITE-LINE (EVAL-WITH-HISTORY (WITH-INPUT-FROM
4   0                           (WITH-OUTPUT-TO-CURRENT-POINT (LAMBDA () (WRITE
5   0         ^G-INTERCEPTOR    (LET ((VALUE (CALL-WITH-CURRENT-CONTINUATION (L
6        COMMAND-READER-LOOP    (LET ((VALUE (CALL-WITH-CURRENT-CONTINUATION (L
7        COMMAND-READER-LOOP    (BEGIN (LET ((VALUE (CALL-WITH-CURRENT-CONTINUA

The first column in the history lists the subproblem level of each Expression, and the second column lists the reduction number. The Procedure Name column lists the procedure in which the Expression appears.

In this history, subproblems 0, 1, and 2 give the evaluation history of the fib procedure. In order to evaluate subproblem 2, Scheme had to evaluate subproblem 1, and in order to evaluate subproblem 1, Scheme had to evaluate subproblem 0, which caused the error. Subproblems 3 through 7 are parts of the history of the Scheme Read-Eval-Print (REP) loop, which is responsible for interpreting your typing, evaluating it, and displaying the results. While debugging your programs, you can ignore the subproblems for the Scheme REP loop.

3.3 Where (The Environment Browser)

Where, the Environment Browser, is the Scheme debugging tool for examining and changing variables in environments. Where is particularly useful for examining the state of a Scheme program when an error occurs, because it can display the current values of all variables in the program’s environments.

Start Where from the Debug debugging tool by pressing w while the cursor is in the *Debug buffer.

The buffer in which Where starts shows the environment which was being

examined in Debug, and is called *Environment. An Environment-Browser

buffer is created for each environment being browsed with Where. All Where buffers display “(Environment-Browser)” on the mode line, indicating their major mode.

These keys have special functions when the cursor is in an Environment-Browser buffer:

e Pop up a window (buffer *Eval*) for evaluating Scheme expressions in the environment being browsed.

f Browse the environment which is the value of the variable that the point is on.

p Browse the parent environment of this environment, creating a new

                 Environment-Browser buffer.

q  Leave the current Environment-Browser buffer, killing it.

v Evaluate a single expression in the current environment, prompting for it in the Typein Window.

w Browse an environment, prompting for it in the typein window and

                 creating a new Environment-Browser buffer.

3.4 Trace

Trace is a family of debugging procedures for following the usage of particular procedures in a Scheme program.

(trace-entry procedure)  procedure
(trace-exit procedure)  procedure
(trace-both procedure)  procedure
(trace procedure)  procedure

(untrace )  procedure

(untrace procedure)  procedure

Trace-entry causes Scheme to display a message whenever procedure is entered. Trace-exit causes Scheme to display a message whenever procedure

returns. Trace-both performs both trace-entry and trace-exit. Trace

is the same as trace-entry.

Untrace removes any trace messages set for procedure. With no argument, it removes traces from all procedures.

==> (define (factorial n) (if (< n 2) 1 (* n (factorial (- n 1)))))
FACTORIAL
==> (trace-entry factorial)
==> (trace-exit factorial)
==> (factorial 4)
[Entering <#[COMPOUND-PROCEDURE FACTORIAL] 3>]
[Entering <#[COMPOUND-PROCEDURE FACTORIAL] 2>]
[Entering <#[COMPOUND-PROCEDURE FACTORIAL] 1>]
6
==> (untrace factorial)
==> (trace-exit factorial)

3.4. TRACE 51

==> (factorial 4)
[1 <== <#[COMPOUND-PROCEDURE FACTORIAL] 1>]
[2 <== <#[COMPOUND-PROCEDURE FACTORIAL] 2>]
[6 <== <#[COMPOUND-PROCEDURE FACTORIAL] 3>]
[24 <== <#[COMPOUND-PROCEDURE FACTORIAL] 4>]
24
==> (untrace factorial)
==> (factorial 5)
120
==> (trace-both factorial)
==> (factorial 2)
[Entering <#[COMPOUND-PROCEDURE FACTORIAL] 2>]
[Entering <#[COMPOUND-PROCEDURE FACTORIAL] 1>]
[1 <== <#[COMPOUND-PROCEDURE FACTORIAL] 1>]
[2 <== <#[COMPOUND-PROCEDURE FACTORIAL] 2>]
2
==> _

3.5 Break

Break is a family of debugging procedures for causing particular procedures in a Scheme program to stop for inspection whenever they are used.

Unforunately, in this release of the 6.001 course software, Break does not work under Edwin; it pays no attention to the careful organization of the Edwin screen, but haphazardly writes its own information over Edwin’s. Therefore, before using Break on any procedures, it is recommended that you leave Edwin, entering the “outside” Scheme REP loop; do this by typing ctrl – x z .

The outside REP loop operates similarly to the Edwin Interaction-mode buffer, except that no Edwin commands work; use back space to correct your typing, and enter to send your typing to Scheme. The grey edit key will return you safely to Edwin. We recommend that you stay within Edwin at all times, except when you want to use Break.

Both Debug and Where work in the outside REP loop, but not exactly the same as in Edwin. However, once you learn how to use them in Edwin, the differences will be easy to overcome. To start Debug, type (debug) at Scheme.

When the outside Scheme detects an error, it displays a message describing the error, and switches the prompt from the standard ==> to 2 Error->, but continues as if nothing had happened. At this point, either type ctrl – u to return to the standard prompt, or (debug) to start Debug.

If you start Debug, the prompt will change to 3 Debug-->, and Debug will wait for you to type a one-key command, just like the Debug in Edwin. To see a list of the possible commands, press ? . Type ctrl – u to stop the Debug, returning to the 2 Error-> prompt.

The w key in Debug starts Where, whose prompt is 4 Where-->. Where accepts one-key commands, as well; press ? to list them. From Where, press ctrl – u to stop Where, returning to Debug.

Here is a simple demonstration of the outside REP loop and its debugging tools:

==> foo
Unbound Variable FOO
2 Error-> (debug)
Subproblem Level: 0  Reduction Number: 0
Expression:
FOO
within a MAKE-ENVIRONMENT special form
applied to ()
Debugger
3 Debug--> w
Environment Inspector
4 Where--> c
Frame created by a MAKE-ENVIRONMENT special form
Depth (relative to starting frame): 0
Has bindings:
FACTORIAL = #[COMPOUND-PROCEDURE FACTORIAL]
FIB = #[COMPOUND-PROCEDURE FIB]
4 Where--> _

(break-entry procedure)  procedure
(break-exit procedure)  procedure
(break-both procedure)  procedure
(break procedure)  procedure
(unbreak procedure)  procedure

Break-entry causes Scheme to enter a breakpoint whenever procedure is entered. Break-exit enters a breakpoint whenever procedure returns.

Break-both performs both break-entry and break-exit. Break is the

same as break-entry. Unbreak removes breakpoints from procedure; with no parameter, it removes breakpoints from all procedures.

When a Scheme procedure with a breakpoint is used, it runs normally, except that Scheme creates a simple REP loop when the breakpoint is encountered (either on entering the procedure, or leaving it, or both, depending on how the breakpoint was set). When the REP loop starts, Scheme displays a message which includes the actual parameters to the procedure and, for break-exit and break-both, the value the procedure is returning.

The prompt for the REP loop is 2 Bkpt. At this prompt, any normal Scheme expression is acceptable, including the special expression (proceed), which tells Scheme to continue running the procedure as if the breakpoint had never happened.

Here is a simple demonstration of the use of breakpoints in the outside REP loop:

==> (define (factorial n) (if (< n 2) 1 (* n (factorial (- n 1)))))
FACTORIAL
==> (break-entry factorial)
==> (factorial 3)
[Entering <#COMPOUND-PROCEDURE FACTORIAL] 3>]
Breakpoint on entry
2 Bkpt-> (proceed)
[Entering <#COMPOUND-PROCEDURE FACTORIAL] 2>]
Breakpoint on entry
2 Bkpt-> (proceed)
[Entering <#COMPOUND-PROCEDURE FACTORIAL] 1>]
Breakpoint on entry
2 Bkpt-> (proceed)
6
==> (unbreak factorial)
==> (break-exit factorial)
==> (factorial 2)

[1 <== <#[COMPOUND-PROCEDURE FACTORIAL] 1>]
Breakpoint on exit
2 Bkpt-> n
1
2 Bkpt-> (proceed)
[2 <== <#[COMPOUND-PROCEDURE FACTORIAL] 2>]
Breakpoint on exit
2 Bkpt-> (proceed)
6
==> _

3.6 Error and Breakpoint Procedures

The procedures Scheme uses for signalling errors and breakpoints are available for use in Scheme programs.

(bkpt message object)  syntax

Sets a breakpoint. Displays message and object and enters a breakpoint read-eval-print loop in the current environment.

(breakpoint-procedure message irritant environment)  procedure

Invokes a breakpoint, displaying string message followed by irritant, giving the debugger environment. Used by the special form bkpt.

(error exp_{1} exp_{2} …)  syntax

Signals an error. Displays all the expressions and creates a debugging breakpoint.

(error-procedure message irritant environment)  procedure

Invokes an error, displaying string message followed by irritant, giving the debugger environment. Used by the special form error.

56 CHAPTER 3. DEBUGGING

Scheme Reference

This chapter is a reference manual for the Scheme programming language. Don’t read this chapter to learn Scheme, but turn to it when you need more detail about the language than appears in Structure and Interpretation of Computer Programs [1].

4.1 Notation and terminology

This section describes the notation used in this chapter. It also discusses the lexical conventions for writing Scheme programs.

4.1.1 Notation for this Chapter

In this chapter, in text describing a procedure or special form, the names of all formal parameters are italicized. The names of Scheme procedures, special forms, and variables appear in typewriter-style type. Throughout the chapter, whenever a formal parameter has one of the names listed in the left column of the table below, it must be of the type listed in the right column. For example, a formal parameter refered to as n_{2} in this chapter must be an integer.

obj  any object
x, x_{1}, … x_{j}, … real number
y, y_{1}, … y_{j}, … real number
n, n_{1}, … n_{j}, … integer
k, k_{1}, … k_{j}, … nonnegative integer

4.1.2 Evaluation

The symbol “⟹” in these examples means “evaluates to.” For example,

    (* 5 8)  ⟹ 40

means that the expression (* 5 8) evaluates to 40.

Where the value returned by an expression is marked unspecified, Scheme does not guarantee what the value will be. For example,

(set! x 3) ⟹ unspecified

Feel free to experiment to determine what Scheme returns in any particular case, but remember that a new version of Scheme might return a different value. Avoid writing programs that rely on unspecified values, particularly when working on problem sets.

4.1.3 Numbers

Scheme numbers are expressed exactly as normal numbers, except that scientific notation looks slightly different. In Scheme scientific notation, the numbers of the exponent are not raised, but instead are separated from the base number by the letter e. For example,

123e10 is Scheme notation for 123 × 10^{10}, and -123.45e-1 is Scheme notation for −123.45 × 10^{−1}.

4.1.4 Identifiers

A Scheme identifier is a sequence of letters, digits, and punctuation characters that is not a number. Here are some identifiers:

    lambda           q        <=?
    list->vector     soup     a34kTMNs
    +                V17a     the-word-recursion-has-many-meanings

Upper and lower case forms of a letter are never distinguished except within character and string constants. For example, Foo is the same identifier

as FOO.

Identifiers have several uses within Scheme programs:

• Certain identifiers are reserved for use as special forms, and cannot be used as variables. They are:

         and           else               or
         begin         error              quote
         cond          if                 sequence
         cons-stream   lambda             set!
         define        let                the-environment
         delay         make-environment   unquote

• Any identifier that does not refer to a special form may be used as a variable (see section 4.2).

• When an identifier appears as a quoted constant or within a quoted constant, it denotes a symbol (see section 4.7).

4.1.5 Whitespace and Comments

Whitespace characters are spaces and line breaks (newlines). Whitespace is used to improve readability and to separate tokens (identifiers and numbers) from each other. Whitespace may also occur inside a string value.

A semicolon starts a comment, text which will be seen as whitespace by Scheme. The comment continues from the semicolon to the end of the line. For example:

 ;;; The FACT procedure computes the factorial
 ;;; of a nonnegative integer.
 (define fact
   (lambda (n)
     (if (= n 0)
         1        ;Base case: return 1
         (* n (fact (- n 1))))))

4.1.6 Special Characters in Scheme Notations

Here are the special characters used in Scheme notations:

* / < = > ! ? : $ % _& ~ ^

These characters may be used in identifiers as if they were letters.

. + -

These appear in numbers and identifiers. The period character is also used in the notation for pairs (section 4.6).

( )

Parentheses surround expressions and lists (section 4.6).

'

The single quote character indicates literal data (section 4.3.2).

"

Double quote characters surround string values (section 4.9).

\

Backslash is an escape character within string constants (section 4.9).

[ ] { }

Left and right square brackets and curly braces are reserved for possible future extensions to the language.

#t #f

These are the boolean constants true and false (section 4.5).

#\

Represents the ASCII standard number representing the immediately following character.

#(

Introduces a vector constant (section 4.10).

4.2 Variables and bindings

Any identifier that does not refer to a special form (see section 4.1.4) may be used as a variable. A variable may name a location where a value can be stored. A variable that does so is said to be bound to the location. The set of all bindings in effect at some point in a program is the environment.

Certain expressions create new locations and bind variables to them. The most fundamental of these binding constructs is the lambda expression, because all other binding constructs can be explained in terms of lambda expressions. See section 4.3.5.

Like Algol and Pascal, and unlike most other dialects of Lisp except Common Lisp, Scheme is statically scoped and has block structure. To each place where a variable is bound in a program there corresponds a region of the program text within which the binding is effective. The region is determined by the particular binding construct that establishes the binding; if the binding is established by a lambda expression, for example, then its region is the entire lambda expression. Every reference to or assignment of a variable refers to the binding of the variable that established the innermost of the regions containing the use. If there is no binding of the variable whose region contains the use, then the use refers to the binding for the variable in the top level environment; if there is no binding for the identifier, it is said to be unbound.

4.3 Expressions

A Scheme expression is a piece of code that returns a value. Types of expressions include variable references, literals, procedure calls, and special forms (see section 4.1.4). This section describes all Scheme expression types except conditionals and logical operations, which are described in section 4.5.

4.3.1 Variable references

variable  syntax

An expression consisting of a variable (section 4.2) is a variable reference. The value of the variable reference is the value stored in the location to which the variable is bound. It is an error to reference an unbound variable.

    (define x 28)
    x  ⟹ 28

4.3.2 Literals

(quote datum)  syntax
'datum  syntax
constant  syntax

(quote datum) evaluates to datum. Datum may be any printed representation of a Scheme object. This notation is used to include literal constants in Scheme code.

    (quote a)  ⟹ a
    (quote #(a b c))  ⟹ #(a b c)
    (quote (+ 1 2))  ⟹ (+ 1 2)

(quote datum) may be abbreviated as 'datum. The two notations are equivalent in all respects.

    'a  ⟹ a
    '#(a b c)  ⟹ #(a b c)
    '(+ 1 2)  ⟹ (+ 1 2)
    '(quote a)  ⟹ (quote a)
    ''a  ⟹ (quote a)

Numeric constants, string constants, character constants, and boolean constants evaluate “to themselves”; they need not be quoted.

    '"abc"  ⟹ "abc"
    "abc"  ⟹ "abc"
    '145932  ⟹ 145932
    145932  ⟹ 145932
    '#t  ⟹ #t
    #t  ⟹ #t

4.3.3 Procedure calls

(operator operand_{1} …)  syntax

A procedure call is written by enclosing in parentheses expressions for the procedure to be called and the arguments to be passed to it. The operator and operand expressions are evaluated (in an indeterminate order) and the resulting procedure is passed the resulting arguments.

    (+ 3 4)  ⟹ 7
    ((if #f + *) 3 4)  ⟹ 12

Procedure calls are also called combinations.

4.3.4 Lambda expressions

(lambda formals body)  syntax

Syntax: Formals should be a formal arguments list as described below, and body should be a sequence of one or more expressions.

Semantics: A lambda expression evaluates to a procedure. The environment in effect when the lambda expression was evaluated is remembered as part of the procedure. When the procedure is later called with some actual arguments, the environment in which the lambda expression was evaluated will be extended by binding the variables in the formal argument list to fresh locations, the corresponding actual argument values will be stored in those locations, and the expressions in the body of the lambda expression will be evaluated sequentially in the extended environment. The result of the last expression in the body will be returned as the result of the procedure call.

    (lambda (x) (+ x x))  ⟹ a procedure
    ((lambda (x) (+ x x)) 4)  ⟹ 8
    (define reverse-subtract
      (lambda (x y) (- y x)))
    (reverse-subtract 7 10)  ⟹ 3
    (define foo
      (let ((x 4))
        (lambda (y) (+ x y))))
    (foo 6)  ⟹ 10

Formals should have one of the following forms:

• (variable_{1} …): The procedure takes a fixed number of arguments; when the procedure is called, the arguments will be stored in the bindings of the corresponding variables.

• variable: The procedure takes any number of arguments; when the procedure is called, the sequence of actual arguments is converted into a newly allocated list, and the list is stored in the binding of the variable.

• (variable_{1} … variable_{n−1} . variable_{n}): If a period surrounded by spaces precedes the last variable, then the value stored in the binding of the last variable will be a list of the actual arguments left over after all the other actual arguments have been matched up against the formal arguments.

    ((lambda x x) 3 4 5 6)  ⟹ (3 4 5 6)
    ((lambda (x y . z) z)
     3 4 5 6)  ⟹ (5 6)

4.3.5 Binding constructs

The binding construct let gives Scheme a block structure, like Algol 60. The syntax of the three constructs is identical, but they differ in the regions they establish for their variable bindings. In a let expression, the initial values are computed before any of the variables become bound.

(let bindings body)  syntax

Syntax: Bindings should have the form

((variable_{1} init_{1}) …),

where each init is an expression, and body should be a sequence of one or more expressions.

Semantics: The inits are evaluated in the current environment (in some unspecified order), the variables are bound to fresh locations holding the results, the body is evaluated in the extended environment, and the value of the last expression of body is returned. Each binding of a variable has body as its region.

    (let ((x 2) (y 3))
      (* x y))  ⟹ 6
    (let ((x 2) (y 3))
      (let ((foo (lambda (z) (+ x y z)))
            (x 7))
        (foo 4)))  ⟹ 9

(let variable bindings body)  syntax

This is an extension of the syntax of let, called “named let” which provides a general looping construct and which may also be used to express recursions.

Named let has the same syntax and semantics as ordinary let except that variable is bound within body to a procedure whose formal arguments are the bound variables and whose body is body. Thus the execution of body may be repeated by invoking the procedure named by variable.

    (let loop ((numbers '(3 -2 1 6 -5))
               (nonneg '())
               (neg '()))
      (cond ((null? numbers) (list nonneg neg))
            ((>= (car numbers) 0)
             (loop (cdr numbers)
                   (cons (car numbers) nonneg)
                   neg))
            ((< (car numbers) 0)
             (loop (cdr numbers)
                   nonneg
                   (cons (car numbers) neg)))))
              ⟹ ((6 1 3) (-5 -2))

4.3.6 Assignments

(set! variable expression)  syntax

Expression is evaluated, and the resulting value is stored in the location to which variable is bound. Variable must be bound in some region or at top level. The result of the set! expression is unspecified.

(define x 2) ⟹ unspecified

    (+ x 1)  ⟹ 3

(set! x 4) ⟹ unspecified

    (+ x 1)  ⟹ 5

4.3.7 Sequencing

(sequence expression_{1} expression_{2} …)  syntax

The expressions are evaluated sequentially from left to right, and the value of the last expression is returned. This expression type is used to sequence side effects such as input and output.

    (sequence (set! x 5)
      (+ x 1))  ⟹ 6
    (sequence (princ "4 plus 1 equals ")
      (princ (+ 4 1)))  ⟹ unspecified
               and prints 4 plus 1 equals 5

Note: Sequence is a synonym for the begin sequencing construct of the Scheme standard.

4.4 Definitions

Definitions are used to establish bindings. Definitions are not valid in all contexts where expressions are allowed. They are valid only at the top level of a program and at the beginning of a body.

A definition should have one of the following forms:

• (define variable expression)

• (define (variable formals) body)

Formals should be either a sequence of zero or more variables, or a sequence of one or more variables followed by a period surrounded by spaces and another variable (as in a lambda expression). This form is equivalent to

(define variable (lambda (formals) body)).

• (define (variable . formal) body) Formal should be a single variable. This form is equivalent to

(define variable (lambda formal body)).

4.4.1 Top level definitions

At the top level of a program, a definition

(define variable expression)

has essentially the same effect as the assignment expression

(set! variable expression)

if variable is bound. If variable is not bound, however, then the definition will bind variable to a new location before performing the assignment, whereas it would be an error to perform a set! on an unbound variable.

    (define add3
      (lambda (x) (+ x 3)))
    (add3 3)  ⟹ 6
    (define first car)
    (first '(1 2))  ⟹ 1

4.4.2 Internal definitions

Definitions are also permitted at the beginning of a body (that is, the body of a lambda, let, or define expression). Such definitions are known as internal definitions as opposed to the top level definitions described above. The variable defined by an internal definition is local to the body. That is, variable is bound rather than assigned, and the region of the binding is the entire body. For example,

    (let ((x 5))
      (define foo (lambda (y) (bar x y)))
      (define bar (lambda (a b) (+ (* a b) a)))
      (foo (+ x 3)))  ⟹ 45

4.5 Booleans and conditionals

The standard boolean objects for true and false are written as #t and #f. t and nil are alternative ways of writing #t and #f, respectively. What really matters, though, are the objects that the Scheme conditional expressions (if, cond, and, or) treat as true or false. The phrase “a true value” (or sometimes just “true”) means any object treated as true by the conditional expressions, and the phrase “a false value” (or “false”) means any object treated as false by the conditional expressions.

Of all the standard Scheme values, only #f and the empty list () count as false in conditional expressions. Everything else, including #t, pairs, symbols, numbers, strings, vectors, and procedures, counts as true.

Boolean constants evaluate to themselves, so they don’t need to be quoted in programs.

    #t  ⟹ #t
    #f  ⟹ #f
    '#f  ⟹ #f

true  variable
false  variable

The variables true and false are initially bound to the values #t and #f respectively. Note that these are ordinary variables, whereas true and false are constants.

    true  ⟹ #t
    false  ⟹ #f
    'false  ⟹ false

4.5.1 Boolean operations

(not obj )  procedure

Not returns #t if obj is false, and returns #f otherwise.

    (not #t)  ⟹ #f
    (not 3)  ⟹ #f
    (not (list 3))  ⟹ #f
    (not #f)  ⟹ #t
    (not '())  ⟹ #t
    (not (list))  ⟹ #t

(and test_{1} …)  syntax

The test expressions are all evaluated. And returns #f if any of its arguments is false, and #t otherwise.

    (and (< 3 4) (> 6 5))  ⟹ #t
    (and (> 3 4) (> 6 5))  ⟹ #f
    (and)  ⟹ #t  ; by convention

(or test_{1} …)  syntax

The test expressions are all evaluated. Or returns #t if any of its arguments is true, and #f otherwise.

    (or (eq? 'x 'y) (eq? 'z 'y))⟹ #f
    (or (> x 0) (= x 0) (< x 0))⟹ #t
    (or)  ⟹ #f  ; by convention

(conjunction test_{1} …)  syntax

The test expressions are evaluated from left to right, and the value of the first expression that evaluates to a false value is returned. Any remaining expressions are not evaluated. If all the expressions evaluate to true values, the value of the last expression is returned. If there are no expressions then #t is returned.

    (conjunction (= 2 2) (> 2 1))
              ⟹ #t
    (conjunction (= 2 2) (< 2 1))
              ⟹ #f
    (conjunction 1 2 'c '(f g))
              ⟹ (f g)
    (conjunction)
              ⟹ #t

(disjunction test_{1} …)  syntax

The test expressions are evaluated from left to right, and the value of the first expression that evaluates to a true value is returned. Any remaining expressions are not evaluated. If all expressions evaluate to false values, the (false) value of the last expression is returned. If there are no expressions then #f is returned.

    (disjunction (= 2 2) (> 2 1))
              ⟹ #t
    (disjunction (= 2 2) (< 2 1))
              ⟹ #t
    (disjunction #f #f #f)
              ⟹ #f
    (disjunction (memq 'b '(a b c))
         (/ 3 0))
              ⟹ (b c)
    (disjunction)
              ⟹ #f

4.5.2 Conditionals

(if test consequent alternate)  syntax
(if test consequent)  syntax

Syntax: Test, consequent, and alternate may be arbitrary expressions. Semantics: An if expression is evaluated as follows: first, test is evalu-

ated. If it yields a true value (see section 4.5), then consequent is evaluated and its value is returned. Otherwise alternate is evaluated and its value is returned. If test yields a false value and no alternate is specified, then the result of the expression is unspecified.

    (if (> 3 2) 'yes 'no)  ⟹ yes
    (if (> 2 3) 'yes 'no)  ⟹ no
    (if (> 3 2)
        (- 3 2)
        (+ 3 2))  ⟹ 1

(cond clause_{1} clause_{2} …)  syntax

Syntax: Each clause should be of the form

(test expression …)

where test is any expression. The last clause may be an “else clause,” which has the form

(else expression_{1} expression_{2} …).

Semantics: A cond expression is evaluated by evaluating the test expressions of successive clauses in order until one of them evaluates to a true value (see section 4.5). When a test evaluates to a true value, then the remaining expressions in its clause are evaluated in order, and the result of the last expression in the clause is returned as the result of the entire cond expression. If the selected clause contains only the test and no expressions, then the value of the test is returned as the result. If all tests evaluate to false values, and there is no else clause, then the result of the conditional expression is unspecified; if there is an else clause, then its expressions are evaluated, and the value of the last one is returned.

    (cond ((> 3 2) 'greater)
          ((< 3 2) 'less))  ⟹ greater
    (cond ((> 3 3) 'greater)
          ((< 3 3) 'less)
          (else 'equal))  ⟹ equal

4.5.3 Testing for equivalence

The three predicates described in this section are used to test whether objects are “the same”. Of the three predicates, eq? is the finest or most discriminating while equal? is the coarsest. Eqv? is slightly less discriminating than eq?. In general, you should use equal? to test the equivalence of structures and eqv? to test the equivalence of atomic objects. See [2] for a careful description of the rationale for these three different predicates.

(eq? obj_{1} obj_{2})  procedure

Eq? is the primitive equivalence predicate. It returns true if obj_{1} and obj_{2} are the same object. Unless you are rather advanced, do not use eq? to test identity of objects other than symbols. In particular, two numbers which are equal in value may not be eq?; use = or eqv? to test numerical equality. Also, two lists which have the same elements and print the same may not be eq?; use equal? to test if lists have the same elements.

For more advanced users only: Two structures are eq? if any attempt to modify one of them modifies the other in the same way; i.e., if the two structures share the same location in memory (see chapter 3 of the 6.001 text).

    (define x '(a b))  ⟹ X
    (define y '(a b))  ⟹ Y
    (define z x)  ⟹ Z
    (eq? x y)  ⟹ #f
    (eq? x z)  ⟹ #t
    (eq? y z)  ⟹ #f
    (set! x 'foo)  ⟹ unspecified
    (set! y 'foo)  ⟹ unspecified

(set! z x) ⟹ unspecified

    (eq? x y)  ⟹ #t
    (eq? x z)  ⟹ #t
    (eq? y z)  ⟹ #t

(eqv? obj_{1} obj_{2})  procedure

Eqv? returns #tif obj_{1} and obj_{2} are: eq? atoms, = numbers, or character strings containing the same characters in the same order with the same capitalization. Two lists are not in general eqv? even if eq? atom by atom. Eqv? is usually the correct predicate for testing the equality of atoms.

    (eqv? "abc" "abc")  ⟹ #t
    (eqv? '(a b c) '(a b c))  ⟹ #f
    (eqv? 67000 67000)  ⟹ #t
    (let ((a '(1 2 3)))
      (let ((b (cons a a)))
        (eqv? (car b) (cdr b))))⟹ #t
    (eqv? (lambda () 1)
          (lambda () 1))  ⟹ #f
    (let ((p (lambda () 1)))
      (eqv? p p))  ⟹ #t

(equal? obj_{1} obj_{2})  procedure

Equal? returns #t if both arguments are eqv? atoms, numbers, or character strings. Equal? list structures are those whose CARs are equal? and whose CDRs are equal?. As illustrated below, eq? and equal? are quite different.

    (eq? '(a b) '(a b))  ⟹ #f
    (equal? '(a b) '(a b))  ⟹ #t
    (define x '(a b))  ⟹ X
    (define y '(a b))  ⟹ Y
    (equal? x y)  ⟹ #t
    (equal? 3 3)  ⟹ #t
    (equal? 67000 67000)  ⟹ #t
    (equal? "abc" "abc")  ⟹ #t

4.6 Pairs and lists

A pair is a structure with two fields called the car and cdr fields (for historical reasons). Pairs are constructed by the procedure cons. The car and cdr fields are accessed by procedures car and cdr, and set by procedures set-car! and

set-cdr!.

Pairs are used primarily to represent lists. A list is either empty or a pair whose car is the first element of the list, and whose cdr is the rest of the list. The length of a list is the number of elements, which is the same as the number of pairs.

The empty list is a special object of its own type (it is not a pair); it has no elements and its length is zero.

The most general notation for Scheme pairs is the “dotted” notation (c_{1} . c_{2}) where c_{1} is the value of the car field and c_{2} is the value of the cdr field. For example (4 . 5) is a pair whose car is 4 and whose cdr is 5. Note that (4 . 5) is the external representation of a pair, not an expression that evaluates to a pair.

A more streamlined notation can be used for lists: the elements of the list are simply enclosed in parentheses and separated by spaces. The empty list is written () . For example,

    (a b c d e)

and

    (a . (b . (c . (d . (e . ())))))

are both representations of a list of symbols.

A chain of pairs not ending in the empty list is called an improper list. Note that an improper list is not a list. The list and dotted notations can be combined to represent improper lists:

    (a b c . d)

is equivalent to

    (a . (b . (c . d)))

Whether a given pair is a list depends upon what is stored in the cdr field. When the set-cdr! procedure is used, an object can be a list one moment and not the next:

    (define x (list 'a 'b 'c))
    (define y x)
    y  ⟹ (a b c)
    (set-cdr! x 4)  ⟹ unspecified
    x  ⟹ (a . 4)
    (eqv? x y)  ⟹ #t
    y  ⟹ (a . 4)

(atom? obj )  procedure

Returns #t if obj is an atom, and #f otherwise. An atom is anything which cannot be further decomposed via car or cdr. In other words, anything that is not a pair is an atom.

    (atom? 3)  ⟹ #t
    (atom? 'car)  ⟹ #t
    (atom? car)  ⟹ #t
    (atom? '(a 3))  ⟹ #f
    (atom? '())  ⟹ #t
    (atom? nil)  ⟹ #t

(list? obj )  procedure

Returns #t if obj is a list, and #f otherwise.

    (list? 'a)  ⟹ #f
    (list? '())  ⟹ #t
    (list? '(a b))  ⟹ #t
    (list? '(a . b))  ⟹ #f

(pair? obj )  procedure

Returns #t if obj is a pair, and #f otherwise. Note that the empty list, '(), is a list but not a pair.

    (pair? '(a . b))  ⟹ #t
    (pair? '(a b c))  ⟹ #t
    (pair? '())  ⟹ #f
    (pair? '#(a b))  ⟹ #f

(cons obj_{1} obj_{2})  procedure

Returns a newly allocated pair whose car is obj_{1} and whose cdr is obj_{2}. The pair is guaranteed to be different (in the sense of eqv?) from every existing object.

    (cons 'a '())  ⟹ (a)
    (cons '(a) '(b c d))  ⟹ ((a) b c d)
    (cons "a" '(b c))  ⟹ ("a" b c)
    (cons 'a 3)  ⟹ (a . 3)
    (cons '(a b) 'c)  ⟹ ((a b) . c)

(car pair)  procedure

Returns the contents of the car field of pair. Note that it is an error to take the car of the empty list.

    (car '(a b c))  ⟹ a
    (car '((a) b c d))  ⟹ (a)
    (car '(1 . 2))  ⟹ 1
    (car '())  ⟹ error

(cdr pair)  procedure

Returns the contents of the cdr field of pair. Note that it is an error to take the cdr of the empty list.

    (cdr '((a) b c d))  ⟹ (b c d)
    (cdr '(1 . 2))  ⟹ 2
    (cdr '())  ⟹ error

(set-car! pair obj )  procedure

Stores obj in the car field of pair. The value returned by set-car! is unspecified.

(set-cdr! pair obj )  procedure

Stores obj in the cdr field of pair. The value returned by set-cdr! is unspecified.

(caar pair)  procedure
(cadr pair)  procedure
⋮                                                     ⋮
(cdddar pair)  procedure
(cddddr pair)  procedure

These procedures are compositions of car and cdr, where for example caddr could be defined by

    (define caddr (lambda (x) (car (cdr (cdr x))))).

Arbitrary compositions, up to four deep, are provided. There are twentyeight of these procedures in all.

(first pair)  procedure
(second pair)  procedure
(third pair)  procedure
(fourth pair)  procedure
(fifth pair)  procedure
(sixth pair)  procedure
(seventh pair)  procedure
(eighth pair)  procedure

These procedures return the first, second, third, ..., eighth element of pair, respectively, in exactly the same manner as would car, cadr, caddr,

cadddr, ....
    (first '((a b) c d))  ⟹ (a b)
    (second '((a b) c d))  ⟹ c
    (eighth '(a b c d e f g h)) ⟹ h

(null? obj )  procedure

Returns #t if obj is the empty list, otherwise returns #f.

(list obj_{1} …)  procedure

Returns a list of its arguments.

    (list 'a (+ 3 4) 'c)  ⟹ (a 7 c)
    (list)  ⟹ ()

(list* obj_{1} obj_{2} …)

List* conses together an arbitrary number of arguments. It constructs a pair whose car is obj_{1} and whose cdr is (list* obj_{2} …). When it has only two arguments, list* behaves in the same way as cons.

    (list* 'a 'b 'c)  ⟹ (a b . c)
    (list* '(a b) 'c '(d e))  ⟹ ((a b) c d e)
    (list* 'a 'b)  ⟹ (a . b)
    (list* 'a)  ⟹ a

(length list)  procedure

Returns the length of list.

    (length '(a b c))  ⟹ 3
    (length '(a (b) (c d e))) ⟹ 3
    (length '())  ⟹ 0

(append list_{1} list_{2})  procedure
(append list …)  procedure

Returns a list consisting of the elements of the first list followed by the elements of the other lists.

    (append '(x) '(y))  ⟹ (x y)
    (append '(a) '(b c d))  ⟹ (a b c d)
    (append '(a (b)) '((c)))  ⟹ (a (b) (c))

The resulting list is always newly allocated, except that it shares structure with the last list argument. The last argument may actually be any object; an improper list results if it is not a proper list.

    (append '(a b) '(c . d))  ⟹ (a b c . d)
    (append '() 'a)  ⟹ a

(reverse list)  procedure

Returns a newly allocated list consisting of the elements of list in reverse order.

    (reverse '(a b c))  ⟹ (c b a)
    (reverse '(a (b c) d (e (f))))
              ⟹ ((e (f)) d (b c) a)

(list-tail list k)  procedure
(nthcdr k list)  procedure

Returns the sublist of list obtained by omitting the first k elements.

List-tail could be defined by

    (define list-tail
      (lambda (x k)
        (if (zero? k)
            x
            (list-tail (cdr x) (- k 1)))))

For historical reasons, (nthcdr k list) is the same as (list-tail list k).

    (list-tail '(a b c d) 2)  ⟹ (c d)
    (nthcdr 2 '(a b c d))  ⟹ (c d)

(last list)  procedure

Returns the last pair of list.

    (last '(a b c))  ⟹ (c)

(list-ref list k)  procedure
(nth k list)  procedure

Both list-ref and nth return the kth element of list, where numbering starts with zero. (This is the same as the car of (list-tail list k).)

    (list-ref '(a b c d) 2)  ⟹ c
    (nth 2 '(a b c d))  ⟹ c

(member obj list)  procedure(memq obj list)  procedure
(memv obj list)  procedure

Returns the first sublist of list whose car is obj . If obj does not occur in list, returns #f. Memq uses eq? to compare obj with the elements of list,

while memv uses eqv? and member uses equal?.
    (memq 'a '(a b c))  ⟹ (a b c)
    (memq 'b '(a b c))  ⟹ (b c)
    (memq 'a '(b c d))  ⟹ #f
    (memq (list 'a) '(b (a) c)) ⟹ #f
    (member (list 'a)
            '(b (a) c))  ⟹ ((a) c)
    (memq 101 '(100 101 102)) ⟹ unspecified
    (memv 101 '(100 101 102)) ⟹ (101 102)

(assoc obj alist)  procedure
(assq obj alist)  procedure
(assv obj alist)  procedure

Alist (for “association list”) must be a list of pairs. Finds the first pair in alist whose car field is obj and returns that pair. If no pair in alist has obj as its car, returns #f. Assq uses eq? to compare obj with the car fields of the pairs in alist, while assv uses eqv? and assoc uses equal?.

4.7. SYMBOLS 81

(define e '((a 1) (b 2) (c 3)))
(assq 'a e)  ⟹ (a 1)
(assq 'b e)  ⟹ (b 2)
(assq 'd e)  ⟹ #f
(assq (list 'a) '(((a)) ((b)) ((c))))
                            ⟹ #f
(assq 5 '((2 3) (5 7) (11 13)))

⟹ unspecified

(assv 5 '((2 3) (5 7) (11 13)))
                            ⟹ (5 7)
(assoc (list 'a) '(((a)) ((b)) ((c))))
                            ⟹ ((a))

Note: Although they are ordinarily used as predicates, memq, memv, member, assq, assv, and assoc do not have question marks in their names because they return useful values rather than just #t or #f.

4.7 Symbols

Symbols are objects whose usefulness rests on the fact that two symbols are identical (in the sense of eqv?) if and only if their names are spelled the same way. The rules for writing a symbol are exactly the same as the rules for writing an identifier; see section 4.1.4.

(symbol? obj )  procedure

Returns #t if obj is a symbol, otherwise returns #f.

(symbol? 'foo)  ⟹ #t
(symbol? (car '(a b)))  ⟹ #t
(symbol? "bar")  ⟹ #f

(alphaless? symbol_{1} symbol_{2} )  procedure

Returns #t or #f according to whether the name of symbol_{1} alphabetically precedes the name of symbol_{2}.

    (alphaless? 'ab 'b)  ⟹  #t
    (alphaless? 'a 'a)  ⟹  #f

(explode symbol)  procedure

Returns a list of one-character symbols or digits that are the letters in the name of symbol.

    (explode 'gleep35)  ⟹  (G L E E P 3 5)

(implode list)  procedure

The argument must be a list of character symbols or integers. Implode returns a symbol whose name is the concatenation of the names of elements in the list.

    (implode '(g l e e p 3 5)) ⟹  GLEEP35

(char n)  procedure

Returns the ASCII character (symbol) whose ASCII code is n.

    (char 65)  ⟹ A

(ascii symbol)  procedure

Returns the ASCII code of the single-character symbol symbol. All alphabetic characters are regarded as upper case, because symbols do not retain the case in which they are typed.

    (ascii 'a)  ⟹ 65

(generate-uninterned-symbol symbol)  procedure

Returns a symbol that is guaranteed to be different (not eqv?) from any other symbol. The printed representation of the new symbol will begin with the characters of symbol.

Note: The “name” of an uninterned symbol is convenience for the human reader. You cannot reference an uninterned symbol by quoting its name.

    (define s (generate-uninterned-symbol 'fact))

⟹ unspecified

s  ⟹  something of the form FACT342

    (eqv? s s)  ⟹ #t
    (eqv? s 'FACT342)  ⟹ #f

4.8 Numbers

Section 4.1.1 lists the names used here to specify restriction on the types of arguments these numerical procedures will accept.

(number? obj )  procedure
(integer? obj )  procedure

These numerical type predicates can be applied to any kind of argument, including non-numbers. They return true if the object is of the named type. In general, if a type predicate is true of a number then all higher type predicates are also true of that number.

(zero? z)  procedure

(positive? x)  procedure
(negative? x)  procedure

(odd? n)  procedure
(even? n)  procedure

These numerical predicates test a number for a particular property, returning #t or #f.

(= z_{1} z_{2})  procedure
(< x_{1} x_{2})  procedure

(> x_{1} x_{2})  procedure
(<= x_{1} x_{2})  procedure
(>= x_{1} x_{2})  procedure

These procedures return #t if their arguments are (respectively): numerically equal, monotonically increasing, monotonically decreasing, monotonically nondecreasing, or monotonically nonincreasing.

(max x_{1} x_{2})  procedure
(max x_{1} x_{2} …)  procedure
(min x_{1} x_{2})  procedure
(min x_{1} x_{2} …)  procedure

These procedures return the maximum or minimum of their arguments.

(+ z_{1} z_{2})  procedure
(+ z_{1} …)  procedure
(* z_{1} z_{2})  procedure
(* z_{1} …)  procedure

These procedures return the sum or product of their arguments.

    (+ 3 4)  ⟹ 7
    (+ 3)  ⟹ 3
    (+)  ⟹ 0
    (* 4)  ⟹ 4
    (*)  ⟹ 1

(- z_{1} z_{2})  procedure
(- z_{1} z_{2} …)  procedure
(/ z_{1} z_{2})  procedure
(/ z_{1} z_{2} …)  procedure

With two or more arguments, these procedures return the difference or quotient of their arguments, associating to the left. With one argument, however, they return the additive or multiplicative inverse of their argument.

    (- 3 4)  ⟹ -1
    (- 3 4 5)  ⟹ -6
    (- 3)  ⟹ -3
    (/ 3 4 5)  ⟹ 3/20
    (/ 3)  ⟹ 1/3

4.8. NUMBERS 85

(1+ z)  procedure

This procedure returns a value one greater than its argument.

    (1+ 3)  ⟹ 4

(-1+ z)  proecedure

This procedure returns a value one less than its argument.

    (-1+ 3)  ⟹ 2

(abs z)  procedure

Abs returns the magnitude of its argument.

    (abs -7)  ⟹ 7
    (abs -3+4i)  ⟹ 5

(quotient n_{1} n_{2})  procedure
(remainder n_{1} n_{2})  procedure

(integer-divide n_{1} n_{2})  procedure

These are intended to implement number-theoretic (integer) division: For positive integers n_{1} and n_{2}, if n_{3} and n_{4} are integers such that n_{1} = n_{2}n_{3} +n_{4} and 0 ≤ n_{4} < n_{2}, then

    (quotient n_{1} n_{2})  ⟹ n_{3}
    (remainder n_{1} n_{2})  ⟹ n_{4}
    (integer-divide n_{1} n_{2})  ⟹ (n_{3} . n_{4})
   integer-divide returns the cons of what quotient and remainder

would return given the same arguments.

For all integers n_{1} and n_{2} with n_{2} not equal to 0,

    (= n_{1} (+ (* n_{2} (quotient n_{1} n_{2}))

             (remainder n_{1} n_{2})))

                                ⟹ #t

The value returned by quotient always has the sign of the product of its arguments. Remainder always has the sign of the dividend.

    (remainder 13 4)  ⟹ 1
    (remainder -13 4)  ⟹ -1
    (remainder 13 -4)  ⟹ 1
    (remainder -13 -4)  ⟹ -1

(gcd n_{1} …)  procedure

These procedures return the greatest common divisor or least common multiple of their arguments. The result is always non-negative.

    (gcd 32 -36)  ⟹ 4
    (gcd)  ⟹ 0

(floor x)  procedure
(ceiling x)  procedure

(truncate x)  procedure

(round x)  procedure

These procedures create integers and rationals.

Floor returns the largest integer not larger than x. Ceiling returns the smallest integer not smaller than x. Truncate returns the integer of maximal absolute value not larger than the absolute value of x. Round returns the closest integer to x, rounding to even when x is halfway between two integers.

Note: Round rounds to even for consistency with the rounding modes required by the IEEE floating point standard.

(exp z)  procedure
(log z)  procedure
(sin z)  procedure
(cos z)  procedure
(tan z)  procedure
(atan y x)  procedure

Log computes the natural logarithm of z (not the base 10 logarithm). Atan returns the arctangent, in radians, of the quotient of its arguments.

For nonzero x, the value of log x is defined to be the one whose imaginary part lies in the range −π (exclusive) to π (inclusive). (Log 0) is undefined.

(sqrt z)  procedure

Returns the square root of z.

(expt z_{1} z_{2})  procedure

Returns z_{1} raised to the power z_{2}:

z_{1}^{z_{2}} = e^{z_{2} log z_{1}}

0^{0} is defined to be equal to 1.

(random k)  procedure

Returns an integer chosen at random between 0 and k − 1, inclusive. The argument k must be a positive integer.

4.9 Strings

Strings are sequences of characters. Strings are written as sequences of characters enclosed within double quotes ("). A double quote inside a string is created by \", as in

    "The word \"recursion\" has many meanings."

To type \ on the Chipmunk keyboard, hold down shift and press the ) on the numeric keypad on the right side of the keyboard; shift with 0 (zero) will not work.

4.10 Vectors

Vectors are structures whose elements are indexed by integers. The first element in a vector is indexed by zero, and the last element is indexed by one less than the length of the vector. The printed representation for vectors is a # followed by the sequence of elements, enclosed in parentheses. For example, a vector of length 3 containing the number zero in element 0, the list (2 2 2 2) in element 1, and the string "Anna" in element 2 can be written as following:

    #(0 (2 2 2 2) "Anna")

Note that this is the external representation, not an expression evaluating to a vector. Like lists, vector constants must be quoted:

    '#(0 (2 2 2 2) "Anna")  ⟹ #(0 (2 2 2 2) "Anna")

Vectors are created by the constructor procedures vector and vector-cons. The elements are accessed and assigned by the procedures vector-ref and

vector-set!.

(vector? obj )  procedure

Returns #t if obj is a vector, otherwise returns #f.

(vector-cons size fill)  procedure

Vector-cons returns a newly allocated vector of size elements, each initialized to fill.

(vector obj …)  procedure

Returns a newly allocated vector whose elements contain the given arguments. Analogous to list.

    (vector 'a 'b 'c)  ⟹ #(a b c)

(vector-size vector)  procedure

Returns the number of elements in vector.

(vector-ref vector k)  procedure

k must be a nonnegative integer less than (vector-length vector). Vector-ref returns the contents of element k of vector.

    (vector-ref '#(1 1 2 3 5 8 13 21) 5) ⟹ 8

(vector-set! vector k obj )  procedure

k must be a nonnegative integer less than (vector-length vector). Vector-set! stores obj in element k of vector. The value returned by vector-set! is unspecified.

    (let ((vec (vector 0 '(2 2 2 2) "Anna")))
      (vector-set! vec 1 '("Sue" "Sue"))
      vec)
              ⟹ #(0 ("Sue" "Sue") "Anna")

4.11 Control features

This chapter describes various primitive procedures that control the flow of program execution in special ways.

(apply proc args)  procedure

Proc must be a procedure and args must be a list. Apply calls proc with the elements of args as the actual arguments.

    (apply + (list 3 4))  ⟹ 7
    (define compose
      (lambda (f g)
        (lambda args
          (f (apply g args)))))
    ((compose sqrt *) 12 75)  ⟹ 30

(mapcar proc list_{1} list_{2} …)  procedure

Proc must be a procedure of which takes as many arguments as there are lists supplied to mapcar. Mapcar returns a list whose first element is proc applied to the first element of eachlist, whose second element is proc applied to the second element of the list, and so on. Mapcar stops when it reaches the end of the shortest list.

    (mapcar length '((a b) (c d) (e (f g) h)))
              ⟹ (2 2 3)
    (mapcar + '(1 2 3) '(4 5 6))
              ⟹ (5 7 9)
    (mapcar * '(1 2) '(3 4 5) '(6 7 8 9))
              ⟹ (18 56)

(mapc proc list_{1} list_{2} …)  procedure

Proc must be a procedure which takes as many arguments as there are lists supplied to mapc. Mapc applied proc to the first element of ech list, to the second element of each list, and so on. The difference between mapc and mapcar is that mapcar returns a list of values, while mapc does not. The procedure proc is usually applied for effect, and the value returned by mapc should be ignored.

4.12 Streams and delayed evaluation

A stream is a structure with two fields called the head and the tail. Streams are created by cons-stream. The head and tail are accessed using the procedures head and tail. Streams are used for representing sequences of elements, which are retrieved as the heads of successive tails of the stream. In this way, a stream is like a list. The difference is that the items in the stream are delayed, that is, they are computed when they are accessed rather than when the stream is constructed. The empty stream is stream that has no elements. See chapter 3 of [1] for information on programming with streams.

(cons-stream obj_{1} obj_{2})  syntax

Returns a stream whose head is obj_{1} and whose tail is obj_{2}. Cons-stream is syntax rather than a procedure because it does not evaluate its second argument.

(head stream)  procedure

Returns the head of the given stream.

(tail stream)  procedure

Returns the tail of the given stream.

the-empty-stream  variable

A variable initially bound to the empty stream.

(empty-stream? obj )  procedure

Returns #t or #f depending on whether obj is the empty steam.

(delay expression)  syntax

The delay construct, together with the procedure force, implement lazy evaluation or call by need. (delay expression) returns an object called a promise which at some point in the future may be asked (by the force procedure) to evaluate expression and deliver the resulting value.

(force promise)  procedure

Forces the value of promise (see delay above). If no value has been computed for the promise, then a value is computed and returned. The value of the promise is cached (or “memoized”) so that if it is forced a second time, the previously computed value is returned without any recomputation.

    (force (delay (+ 1 2)))  ⟹ 3
    (let ((p (delay (+ 1 2))))
      (list (force p) (force p)))
                                ⟹ (3 3)

Force and delay are mainly intended for programs written using streams. The following examples should not be considered to illustrate good programming style, but they illustrate the property that the value of a promise is computed at most once.

    (define count 0)
    (define p (delay (sequence (set! count (+ count 1))
       (* x 3))))
    (define x 5)
    count  ⟹ 0

p ⟹ a promise

    (force p)  ⟹ 15

p ⟹ a promise, still

    count  ⟹ 1
    (force p)  ⟹ 15
    count  ⟹ 1

4.13 Input and output

4.13.1 General Terminal and File I/O

Several of the procedures described in this section accept optional arguments. The optional argument channel is a channel objects, as returned by

open-reader-channel or open-printer-channel. If the argument channel

is omitted, the channel is defaulted to the console. For input operations, the optional argument eof is returned on end of file. If eof is omitted, an error is signaled on end of file.

(read-from-keyboard)  procedure

This procedure is used when you want to give input to Scheme while running under Edwin. When you evaluate this procedure, the Scheme interpreter waits to send it an expression, (e.g. by typing execute ) and then returns that expression. While Scheme is waiting, you can use all the Edwin commands normally used in editing. In particular, pressing the abort key will not cause Scheme to stop waiting for input. To force Scheme to stop waiting and return to top level, send it the expression abort.

(photo filename)  procedure
(tofu)  procedure

Photo begins recording the console session to filename, and tofu stops this recording process.

(read)  procedure
(read channel eof )  procedure

Returns the next object parsable from the given input channel, updating channel to point to the first character past the end of the written representation of the object. If an end of file is encountered in the input before any characters are found that can begin an object, then the end of file object eof is returned. This procedure should not be used to get input from the keyboard while Scheme is running in combination with Edwin—use

read-from-keyboard instead.

(newline)  procedure

(newline channel)  procedure

Writes a carriage return and line feed to channel. Returns an unspecified value.

(print obj )  procedure
(print obj channel)  procedure
(prin1 obj )  procedure
(prin1 obj channel)  procedure
(princ obj )  procedure
(princ obj channel)  procedure

Print prints the value of obj on the console, or channel, if specified, preceding it with a carriage-return and line-feed. If obj is a string, it is output surrounded by double quotes.

Prin1 behaves exactly the same as print, except that it does not precede the output with a carriage-return and line-feed.

Princ behaves exactly the same as prin1, except that it does not surround output strings with double quotes, and double quotes which are part of the string are not displayed preceded by backslash “\”.

(print-depth)  procedure
(print-depth n)  procedure

Returns the depth to which nested list structures will be printed. If null, no restrictions are placed on print depth. If given the argument n, print-depth changes the print depth to n.

(print-breadth)  procedure
(print-breadth n)  procedure

Returns the number of elements of list strcture that will be printed out. If null, no restrictions are placed on print breadth. If given the argument n, print-breadth changes the print breadth to n.

4.13.2 Advanced Terminal and File I/O

Several of the procedures described in this section accept optional arguments. The optional argument channel is a channel object, as returned by

open-read-channel or open-printer-channel. If the argument channel is

omitted, the channel is defaulted to the console. For input operations, the optional argument eof can be included. On end of file, the object eof will be returned as the value of the input operation. If omitted, an error is signaled on end of file.

(close-channel channel)  procedure

Closes an opened input or output channel. channel is an object created

by open-reader-channel or open-printer-channel.

(delete-file filename)  procedure

Deletes the file specified by character string filename.

(file-exists? filename)  procedure

Returns #t if a file named filename exists, and #f otherwise. Filename is a character string.

(open-reader-channel filename)  procedure

Returns a channel object which can be used for input from the file specified by character string filename. If the file does not exist, an error occurs.

(open-printer-channel filename)  procedure

Returns a channel object which can be used for output to the file specified by character string filename. If that file already exists, its previous contents will be lost.

(tyi)  procedure
(tyi channel)  procedure
(tyi channel eof )  procedure

Reads a character from the terminal or specified reader channel and returns its ASCII code, an integer. The optional argument eof is an object which will be returned by tyi on end of file.

(tyo n)  procedure
(tyo n channel)  procedure

Outputs the character whose ASCII value is n on the console or specified output channel.

(readch)  procedure
(readch channel)  procedure
(readch channel eof )  procedure

Reads the next character from the terminal or specified input channel and returns it as a symbol. Eof will be returned on end of file.

(peekch)  procedure
(peekch channel)  procedure
(peekch channel eof )  procedure

Peeks at the next character from the terminal or specified input channel without actually reading it, and returns it as a symbol. Eof will be returned on end of file.

(tyipeek)  procedure

(tyipeek channel)  procedure
(tyipeek channel eof )  procedure

Peeks at the next character from the terminal or specified input channel without actually reading it, and returns its ASCII code, an integer. Eof will be returned on end of file.

(initialize-floppy drive name)

Formats a floppy disk for use. Drive is either the symbol left or the symbol right, specifying which floppy to format. Name is a character string specifying the name to give the floppy; it must be ten characters or fewer and end with a colon “:” character. Every floppy must be initialized before it is used the first time, but Edwin automatically formats your disk when you log in for the first time.

    (initialize-floppy 'right "FOO:")

(backup-floppy)

Backs up a floppy disk. When you run this command, you will be asked to insert the source disk in one drive and a target disk in the other drive. The program will initialize the target disk if necessary. Be sure to follow the instructions carefully so as not to confuse the source disk and the target disk.

4.14 Environments and evaluation

An environment is the set of bindings for variables that is in effect at some point in a program. (See section 4.2.) Environments in Scheme are first-class objects. That is, they may be named by variables, passed as arguments to procedures, and returned as the values of procedures. Scheme includes operations for capturing the environment in effect at any point and for specifying that an expression should be evaluated relative to a particular environment.

(eval exp env)  procedure

Returns the result of evaluating exp in the environment env.

(the-environment)  syntax

Evaluating the form the-environment returns the environment in which the form is evaluated.

Note: Scheme’s static-scoping semantics imply that the-environment is not a procedure.

(environment? obj )  procedure

Returns #t or #f depending on whether obj is an environment.

(make-environment exp_{1} exp_{2} . . . )  syntax

Make-environment constructs a new environment that is contained in the environment in which this form is evaluated. The expressions exp_{1}, exp_{2}, … are evaluated sequentially in this new environment, and the environment is returned. The exp_{i} are typically define expressions. A make-environment form is alternate syntax for

    (let () exp_{1} exp_{2} . . . (the-environment))

user-initial-environment  variable

A variable that is initially bound to the environment in which expressions entered from the console are evaluated when Scheme is first run.

4.15 Miscellaneous

(applicable? obj )  procedure

Returns #t if obj can be applied, and #f otherwise. Primitive and compound procedures are applicable.

(object-type obj )  procedure

Returns the primitive datatype of the object obj . The following are the data types that would be encountered in user code:

   • character
   • character-string
   • delayed

98 CHAPTER 4. SCHEME REFERENCE

   • environment
   • list
   • null
   • number
   • primitive-procedure
   • procedure
   • symbol
   • true
   • vector

4.16 Advanced Features

(enable-language-features)  procedure
(disable-language-features)  procedure

The Scheme system includes many more built-in procedures and special forms than are documented in this manual. Most of these are for system programming only. When Scheme is initially loaded, only the procedures in this manual are accessible from the initial user environment. Evaluating enable-language-features makes the additional procedures accessible. Evaluating disable-language-features, in turn, disables these features.

4.17 Graphics

This section describes the basic graphics primitives available on the Chipmunks.

Graphics on the Chipmunks is are displayed separately, but on the same screen as, the standard alphanumeric output. The graphics screen is made up of points which are either on or off. Each point is addressed by its x and y coordinates on the screen, the origin being the middle of the screen. The x direction is numbered from -256 (left) to 255 (right). The y direction is numbers from 194 (top) to -195 (bottom). Some of the graphics procedures deal with a “pen.” The pen can be moved from its current position to another point, either drawing a line or not.

(clear-graphics)  procedure

Clears all graphics from the graphics screen and places the pen at point (0,0) (i.e., the middle of the screen).

(draw-point x y)  procedure

Plots the point at (x, y).

(clear-point x y)  procedure

Erases the point at (x, y).

(position-pen x y)  procedure

Moves the graphics pen to the point specified by the coordinates (x, y).

(draw-line-to x y)  procedure

Draws a line from the current pen position to (x, y) and leaves the pen positioned at (x, y).

(store-graphics filename)  procedure

Saves the image on the graphics screen in the designated file.

(load-graphics filename)  procedure

Interprets the contents of the designated file as a graphics picture, and displays this on the graphics screen.

(print-graphics-file filename)  procedure

Interprets the contents of the designated file as a graphics picture, displays this on the graphics screen, and prints the image on an attached graphics printer. Do not use this command if there is no graphics printer attached to the Chipmunk!

100 CHAPTER 4. SCHEME REFERENCE

Appendix A

Glossary

Buffer A buffer is a block of text that you may examine and change. Whenever you edit in Edwin, you change the contents of a buffer. To preserve a buffer for another time you will use the Chipmunk, you must save the buffer to a file on disk.

Commands A command is an instruction you give Edwin through special keys. For example, use the Find File command to copy a file from a disk into a new buffer. Edwin commands are normally used by pressing the grey function keys across the top of the Chipmunk keyboard. However, if you’re used to Emacs, you may want to use control and escape sequences, instead; in Edwin, most of them work exactly as they work in Emacs. (Use the run key whenever you would normally use esc .)

Cursor The cursor is the blinking underline visible on the screen whenever the Chipmunk is waiting for you to type something. If you type an ordinary character (letter, number, or punctuation), it will be inserted at the current cursor position, and the cursor will move past it.

Extended Commands An extended command is a command used by name, rather than by special keys. To use an extended command, press the extend key ( k_{2} ), followed by the name of the command. Your typing will appear at the bottom of the screen, in the typein window (see below). When you’ve typed the full name of the extended command, press enter .

File A file is a block of text stored on a disk. A file may be copied from a disk into a buffer. A file is created by saving the contents of a buffer on a disk.

Kills The several most recently-deleted regions are kept in the kill ring. Killed text can be retrieved with a yank.

Mark The mark is an invisible point in a buffer. Many commands set it to the buffer location where they were performed. Each buffer has its own mark.

Modes Every buffer has one major mode, and maybe some minor modes. Major modes determine special Edwin behavior particular to the language you are using (e.g.,

102 APPENDIX A. GLOSSARY

Scheme or English). Minor modes add special features regardless of the language you are using in the buffer.

Point The current cursor location in each buffer is called the point. The cursor is just a reflection of the point in the current buffer.

Region Text between the point and the mark is called the region.

Saving To save is to create a disk file from a buffer. The file and the buffer are identical, but only the file remains when you logout; the buffer is erased.

Window A window is a rectangular area on the screen. Each window displays part of some buffer. Because most buffers are too big to fit in one window, only part of the buffer is visible at any time; you can see other parts by using Edwin commands to scroll through the buffer.

Bibliography

[1] Harold Abelson and Gerald Jay Sussman with Julie Sussman. Structure and Interpretation of Computer Programs. MIT Press, Cambridge, 1985.

[2] Jonathan Rees and William Clinger, editors. Revised^{3} Report on the Algorithmic Language Scheme. Newsletter of the ACM Special Interest Group on Programming Languages, November 1986.

[3] Tod Cass. Don’t Panic: A 6.001 User’s guide to the Chipmunk System. January, 1984.

[4] Harold Abelson. Go Ahead – Panic: A 6.003 User’s Guide to the Bobcat System. Spring Semester, 1987.

[5] Richard M. Stallman. Gnu Emacs manual. Fourth Edition, Version 17. February 1986.

104 BIBLIOGRAPHY

Index

105

'() 75
(log 0) 87

* 84 + 84

- 84

-1+ 85

/ 84

1+ 85

< 83

<= 84

= 83; 72, 73

=> 71

> 84

>= 84
abs 85
alphaless? 81
and 69
append 78
applicable? 97
apply 89
ascii 82
assoc 80; 81

assq 80; 81 assv 80; 81 atan 86; 87

atom? 75
backup-floppy 96; 12

binding 61 binding construct 61 binding constructs 61

bkpt 55

bound 61 break 52

break 53
break-both 53
break-entry 53
break-exit 53
breakpoint-procedure 55
caar 77
cadddr 77
caddr 77
cadr 77

call 63 call by need 91 car 76; 73, 74, 75, 77, 78, 80

cdddar 77
cddddr 77

cdr 76; 73, 74, 75, 77, 78

ceiling 86
char 82
character 97
character-string 97
clear-graphics 99
clear-point 99
close-channel 94

combination 63 comment 59

cond 71
conjunction 69

cons 76; 74, 78, 85

cons-stream 91; 90

continuation browser 45

cos 86

debug 45

define 66; 97
delay 91; 92
delayed 97
delete-file 94
disable-language-features 98
disjunction 70
draw-line-to 99
draw-point 99
eighth 77
else 71

empty list 74; 68, 76, 78 empty stream 90

empty-stream? 91
enable-language-features 98

environment 96

environment 98

environment browser 49

environment? 97
eof 92

eq? 72; 73, 80 equal? 73; 72, 80 eqv? 72; 73, 76, 80, 81, 83

error 55
error-procedure 55

escape commands 17

eval 96
even? 83
exp 86
explode 82
expt 87

false 68

#false 68
false 68
fifth 77
file-exists? 94

                                  first 77
                                  floor 86
                                  force 91; 92
                                  fourth 77
                                  gcd 86
                                  generate-uninterned-symbol 83

graphics 98

head 91; 90

identifier 59; 61

                                  if 70
                                  implode 82

improper list 74

                                  initialize-floppy 96
                                  integer-divide 85
                                  integer? 83

internal definition 67

                                  lambda 63

lambda expression 61

                                  last 79

lazy evaluation 91

                                  left 96
                                  length 78

let 64, 65 list 74 list 78; 88, 98

                                  list* 78
                                  list-ref 80
                                  list-tail 79
                                  list? 75
                                  load-graphics 99
                                  load-picture 10
                                  log 86
                                  make-environment 97

mapc 90
mapcar 90
max 84
member 80; 81

memq 80; 81 memv 80; 81

min 84

named let 65

negative? 83
newline 93
nil 68
not 68
nth 80
nthcdr 79
null 98
null? 78

number 58, 83

number 98
number? 83
object-type 97
odd? 83
open-printer-channel 95; 92, 94
open-read-channel 94
open-reader-channel 94; 92
or 69

pair 74

pair? 75
peekch 95
photo 93
position-pen 99
positive? 83
primitive-procedure 98
prin1 93
princ 93
print 93

                                  print-breadth 94
                                  print-depth 94
                                  print-graphics-file 99
                                  print-picture-file 10
                                  proc 90
                                  procedure 98

procedure call 63

promise 91

                                  quote 62
                                  quotient 85; 86
                                  random 87
                                  read 93
                                  read-from-keyboard 92
                                  readch 95

reductions 43 region 61; 64, 65

                                  remainder 85; 86
                                  reverse 79
                                  right 96
                                  round 86
                                  second 77
                                  sequence 66
                                  set! 65
                                  set-car! 77; 74
                                  set-cdr! 77; 74, 75
                                  seventh 77
                                  sin 86
                                  sixth 77

special form 59 specialform 61

                                  sqrt 87
                                  store-graphics 99
                                  store-picture 10

stream 90

subproblems 43

symbol 98
symbol? 81

t 68 tail 91; 90

tan 86
the-empty-stream 91
the-environment 96; 97
third 77
tofu 93

tokens 59 top level environment 61 trace 50

trace 50
trace-both 50
trace-entry 50
trace-exit 50

true 68, 70, 71

#true 68

true 68; 98

truncate 86
tyi 95
tyipeek 95
tyo 95

unbound 61; 62, 67

unbreak 53
untrace 50
user-initial-environment 97

variable 61; 59

vector 88; 98
vector-cons 88
vector-ref 89; 88
vector-set! 89; 88
vector-size 88
vector? 88

where 49 whitespace 59

                                  zero? 83