Massachusetts Institute of Technology

Department of Electrical Engineering and Computer Science

A 6.003 User’s Guide to the Bobcat System Spring Semester 1987

Go ahead—Panic

This manual is an introduction to the Scheme system implemented on the Hewlett-Packard 300 computer, affectionately called the “Bobcat.” It is intended for students in 6.003.^{1} We strongly suggest that you take time to glance through this manual at the beginning of the semester, in order to get a general overview of the system. Bring the manual with you to use as a reference guide while working on 6.003 computer assignments.

1Parts of this manual are adapted from a manual for the 6.001 Chipmunk system written by Todd Cass, from the Revised^{3} Report on Scheme [3] edited by Jonathan Rees and William Clinger, and from the Gnu Emacs Manual [4] by Richard Stallman.

Important

Do not power down a 6.003 computer! The Bobcat

installations run the Unix timesharing system. Powering down a running Unix can make it confused and angry, and lead it to mangle its disk files and perform other antisocial acts. If your computer seems hung, do not try fix to things by power cycling the machine.

Be sure to log out when you are through using the computer. The files you create are not saved on your floppy disk until you log out.

What parts of this manual to read for 6.003

You should skim through chapters 1 and 2—these describe the general setup of the Scheme system on the Bobcat. Chapter 3 lists the specialpurpose “Toolbox” procedures for working with signals and systems that have been added to Scheme for use in 6.003. You should skim this before trying to use Scheme in problem sets. Chapter 4 is a reference manual for Emacs—you needn’t do more than glance at it now, especially if you have used Emacs on Project Athena workstations or the NMode editor in 6.001. Chapter 5 describes the debugging facilities in Scheme. You should look at the introduction to the chapter, but you can avoid the rest, at least until you really get into programming. Chapter 6 is a Scheme reference manual. You might glance at it as a way of refreshing yourself on Scheme, but there’s little point trying to read it through.

Conventions: The following symbols, conventions, and terms are used throughout this manual:

↑ This represents the ctl (control) key, located at the left of the keyboard. ctl behaves like an alternate shift key. The symbol ↑ indicates that the ctl key should be held down while the character immediately following the ↑ symbol is typed. This rule applies only to the first character following the ↑. For example, to type ↑x you should hold down the ctl key and type X. To type ↑x S you should hold down the ctl key and type x, then release the ctl key and type S. To type ↑x↑S you should hold down the ctl key and type x and S. Characters generated while the ctl key is depressed are called control characters. Do not confuse the uparrow symbol on the keyboard (shift-6) with the symbol ↑ for control characters. In all Scheme and Emacs commands, case is not significant in control characters, e.g., ↑X is the same as ↑x.

esc This represents an escape character, sometimes also called a meta character. There are two ways to type an escape character. One is to use the esc key, located at the upper left of the keyboard. esc is a prefix key. Thus, to type esc-X, type sc esc and then (after releasing esc) type X. An alternate (somewhat more convenient) way to type escape characters is to use an extend char key, located at either side of the space bar. extend char acts like an alternate shift key. Thus, to type esc-X hold down extend char and type X. Case is not significant in escape characters, e.g., esc-X is the same as esc-x.

esc-↑ This represents an escape-control character. You can type this either by using esc and ctl or by using extend and ctl. Thus, one way to type esc-↑X is to type esc and then (after releasing esc) to hold down ctl and type X. An alternative way is to hold down both ctl and extend and type X.

return Indicates pressing the return key at the right of the keyboard.

backspace Indicates pressing the backspace key at the upper right of the keyboard.

cursor The cursor is the flashing mark that indicates where the next character typed will be displayed.

Contents

1 Overview of the Bobcat Scheme system 5 1.1 Screen indicators of the system’s status . . . . . . . . . . . . 6 1.2 Entering and leaving the system . . . . . . . . . . . . . . . . 7 1.3 Files and floppy disks . . . . . . . . . . . . . . . . . . . . . . 8

1.3.1 Disks and Files . . . . . . . . . . . . . . . . . . . . . . 8 1.3.2 Non-standard use of floppy disks . . . . . . . . . . . . 9 1.3.3 Initializing Disks . . . . . . . . . . . . . . . . . . . . . 10

1.4 Hardcopy listings and screen images . . . . . . . . . . . . . . 10

2 The Scheme user interface 11

2.1 Running Scheme . . . . . . . . . . . . . . . . . . . . . . . . . 11 2.1.1 Indicators of Scheme’s status . . . . . . . . . . . . . . 12 2.1.2 Evaluating expressions from other buffers . . . . . . . 12

2.2 Multiple buffers and windows . . . . . . . . . . . . . . . . . . 13

2.2.1 Windows and screen configurations . . . . . . . . . . . 13 2.3 Using Program Files . . . . . . . . . . . . . . . . . . . . . . . 16

2.3.1 Loading Problem Set Files . . . . . . . . . . . . . . . . 16 2.4 Printing Transcripts of Scheme Sessions . . . . . . . . . . . . 16

3 The 6.003 Toolbox 17

3.1 Complex numbers and operators . . . . . . . . . . . . . . . . 17 3.1.1 Complex numbers . . . . . . . . . . . . . . . . . . . . 17 3.1.2 Operators . . . . . . . . . . . . . . . . . . . . . . . . . 18

3.2 Polynomials . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 3.3 Rational Functions . . . . . . . . . . . . . . . . . . . . . . . . 22 3.4 Plotting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 3.5 Other definitions . . . . . . . . . . . . . . . . . . . . . . . . . 26 4 The Emacs editor 27

4.1 Basic Emacs concepts . . . . . . . . . . . . . . . . . . . . . . 28 4.2 Getting help . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 4.3 The display . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 4.4 Simple motion . . . . . . . . . . . . . . . . . . . . . . . . . . 30 4.5 Scrolling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 4.6 Text motion . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 4.7 Transposition . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 4.8 Queries and fixes . . . . . . . . . . . . . . . . . . . . . . . . . 31

4.8.1 Query replace . . . . . . . . . . . . . . . . . . . . . . . 31 4.9 Deletes, kills, and yanks . . . . . . . . . . . . . . . . . . . . . 32 4.10 Manipulating Scheme expressions . . . . . . . . . . . . . . . . 32 4.11 Evaluating Scheme expressions . . . . . . . . . . . . . . . . . 33 4.12 Buffers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 4.13 Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 4.14 Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 4.15 Searching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 4.16 Case changes . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 4.17 Filling and centering . . . . . . . . . . . . . . . . . . . . . . . 34 4.18 Marks and registers . . . . . . . . . . . . . . . . . . . . . . . . 35 4.19 Macros and repetition . . . . . . . . . . . . . . . . . . . . . . 35 4.20 Subsystems . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 4.21 Exiting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 4.22 Some Editing Modes . . . . . . . . . . . . . . . . . . . . . . . 35

5 Debugging 37 5.1 Read-Eval-Print Levels . . . . . . . . . . . . . . . . . . . . . . 39 5.2 Breakpoint and Error REP Loops . . . . . . . . . . . . . . . . 40 5.3 Trace and Break . . . . . . . . . . . . . . . . . . . . . . . . . 41 5.4 The Environment Examiner: Where . . . . . . . . . . . . . . 43 5.5 The Scheme Debugger: Debug . . . . . . . . . . . . . . . . . 46 5.6 An Extended Debugging Session . . . . . . . . . . . . . . . . 50

6 Scheme language reference 57

6.1 Notation and terminology . . . . . . . . . . . . . . . . . . . . 57 6.1.1 Format of entries . . . . . . . . . . . . . . . . . . . . . 57 6.1.2 Evaluation examples . . . . . . . . . . . . . . . . . . . 59 6.1.3 Unspecified values . . . . . . . . . . . . . . . . . . . . 59 6.1.4 Identifiers . . . . . . . . . . . . . . . . . . . . . . . . . 59 6.1.5 Syntax of numbers . . . . . . . . . . . . . . . . . . . . 60 6.1.6 Whitespace and comments . . . . . . . . . . . . . . . 61 6.1.7 Other notations . . . . . . . . . . . . . . . . . . . . . . 61

6.2 Variables and bindings . . . . . . . . . . . . . . . . . . . . . . 62 6.3 Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63

6.3.1 Variable references . . . . . . . . . . . . . . . . . . . . 63 6.3.2 Literals . . . . . . . . . . . . . . . . . . . . . . . . . . 63 6.3.3 Procedure calls . . . . . . . . . . . . . . . . . . . . . . 64 6.3.4 Lambda expressions . . . . . . . . . . . . . . . . . . . 64 6.3.5 Binding constructs . . . . . . . . . . . . . . . . . . . . 65 6.3.6 Assignments . . . . . . . . . . . . . . . . . . . . . . . 68 6.3.7 Sequencing . . . . . . . . . . . . . . . . . . . . . . . . 68 6.3.8 Quasiquotation . . . . . . . . . . . . . . . . . . . . . . 69

6.4 Definitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 6.4.1 Top level definitions . . . . . . . . . . . . . . . . . . . 70 6.4.2 Internal definitions . . . . . . . . . . . . . . . . . . . . 71

6.5 Booleans and conditionals . . . . . . . . . . . . . . . . . . . . 71 6.5.1 Boolean operations . . . . . . . . . . . . . . . . . . . . 72 6.5.2 Conditionals . . . . . . . . . . . . . . . . . . . . . . . 73 6.5.3 Testing for equivalence . . . . . . . . . . . . . . . . . . 74

6.6 Pairs and lists . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 6.7 Symbols . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82 6.8 Numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 6.9 Characters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88 6.10 Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89 6.11 Vectors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89 6.12 Control features . . . . . . . . . . . . . . . . . . . . . . . . . . 91 6.13 Streams and delayed evaluation . . . . . . . . . . . . . . . . . 92 6.14 Input and output . . . . . . . . . . . . . . . . . . . . . . . . . 94

6.14.1 Ports . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94 6.14.2 Input . . . . . . . . . . . . . . . . . . . . . . . . . . . 96 6.14.3 Output . . . . . . . . . . . . . . . . . . . . . . . . . . 97

6.15 Environments and evaluation . . . . . . . . . . . . . . . . . . 98 6.16 Errors, breakpoints, and debugging . . . . . . . . . . . . . . . 99 6.17 Miscellaneous . . . . . . . . . . . . . . . . . . . . . . . . . . . 101 6.18 Graphics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102

Chapter 1

Overview of the Bobcat Scheme system

The HP 300 (Bobcat) computer uses a Motorola 68020 microprocessor. As configured in the 6.003 lab, each Bobcat has approximately 7 megabytes of physical memory, two 55-megabyte hard disks, and two 3\frac{1}{2}-inch floppy disk drives. The computers are networked to provide access from each machine to a laser printer. Student program files are stored on personal floppy disks.

The Bobcat computer runs the Unix timesharing system, but 6.003 Scheme uses a protected subsystem that always runs the Emacs editor and Scheme. If you are familiar with Unix and would like to play around in the Unix shell, ask a lab TA for assistance. Here is the general procedure for using Scheme on a Bobcat:

• Log in to Unix as u6003. No password is required. If you have a floppy disk, insert it into the left-hand drive. The system will copy all the files from your floppy disk onto the Bobcat hard disk so that they can be rapidly accessed. Then the system will load Scheme and start the Emacs editor. You can use the editor to type, modify, and evaluate Scheme expressions, and to load and save files. In general, all interaction with the Scheme system is via the editor.^{1}

8 CHAPTER 1. OVERVIEW OF THE BOBCAT SCHEME SYSTEM

• The editor can deal with a number of separate chunks of text called buffers. Initially, when you load Scheme, you will be typing at a buffer called *scheme*. Whenever you evaluate a Scheme expression, the result will be inserted at the cursor position in *scheme* buffer. (See section 2.1.)

1This is unlike the 6.001 system, in which you are sometimes typing at the editor and sometimes typing directly at the Scheme read-eval-print loop. We hope that the 6.003 system will be easier to use.

• Normally, you will read in a file, or create a new file, that holds the programs you are developing. Thus, you will normally be using two buffers—the *scheme* buffer for holding interactions with Scheme, and another buffer for holding your program text. You can evaluate a Scheme expression that appears in either buffer, but the result of any evaluation will always appear in the *scheme* buffer. Thus, in developing a program, you would normally type the definition into the file buffer and evaluate this definition by typing esc-z. (See section 2.1.2.) Then you would switch to the *scheme* buffer to test your program.

• You can view more than one buffer at once by directing the editor to divide the screen into separate areas called windows. You can reserve a window on the screen for displaying graphics. By using one, two, or three windows, you can choose to view the *scheme* buffer, some other buffer, your graphics, or any combination of these.

• When you are satisfied with a program, you can save the buffer containing it as a file on the Bobcat’s local hard disk. It is a good idea to save your programs from time to time as you make changes.

• When you are done, log out. Any files you created on the hard disk will be copied to your floppy disk, which you should remove from the drive and take with you. Do not remove your floppy disk from the drive until after you log out. Otherwise, your new files will not be copied to the floppy disk.

1.1 Screen indicators of the system’s status

When using the Bobcat for 6.003, you are almost always interacting by typing at the editor. When the editor is running, the screen will be divided into regions called windows. At the bottom of each window there will appear a mode line, displayed in reverse video. Information in the mode line tells you the status of Scheme and of Emacs. For example, the mode line

-----Emacs: laplace  I 1 [REP Loop] (Scheme)57%-----

identifies that the name of the buffer is laplace, that Emacs is currently configured in Scheme mode, and that the part of the buffer being examined is 57% of the way through the whole buffer. Saying that Emacs is running in Scheme mode means that, in addition to the ordinary Emacs text-manipulation commands, there are also special commands to aid you in running Scheme. The I means that Scheme is waiting for input (as opposed to running). The 1 and REP Loop mean that Scheme is at level 1 running its read-eval-print loop. Section 2.1 tell how to interpret these indicators of Scheme’s status.

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

    -**--Emacs: laplace  I 1 [REP Loop] (Scheme)57%-----

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

Certain buffers used by the system, such as buffers used for displaying graphics and disk directories, are read-only. This is indicated by two percent signs at the left of the mode line. For example, the mode line

    -%%--Emacs: graphics I 1 [REP Loop] (Scheme)57%---

indicates that the graphics buffer is read-only—Emacs will not let you modify it.

Most of the time when you are interacting with Scheme, you will be typing in a special buffer called *scheme*. This is the buffer in which the Scheme interpreter prints the results of evaluating expressions.

At the very bottom of the screen, below the mode line for the lowest window, is a one-line area called the echo area. Often, the system will display messages in this area and ask you to repond. When you type your reply, it will also appear in the echo area. The echo area is also used for typing Emacs extended commands. To invoke an extended command, type esc-x followed by the command name and press return. Your typing will appear in the echo area.

1.2 Entering and leaving the system

The Bobcats are normally left running at all times. When you are through using a machine you should log out, using the Emacs extended command

esc-X logout.

When a Bobcat is not in use (when it is first turned on, or after someone logs out) it will be running a login loop; and a message asking you to log in will appear near the top of the screen. Type u6003 and press return. This will start the Emacs editor and load the 6.003 Scheme system, which takes about a minute. Next, the system will ask you if you want to use a floppy disk. If you have a disk, insert it into the left-hand of the two disk drives at the top of the Bobcat. Be sure that the disk label is face up and toward you. The system will check that the name on the disk matches your user name and warn you if the two names do not match. If the floppy disk is being used for the first time, the system will offer to initialize the disk.

The login procedure copies the files from your floppy disk onto the Bobcat hard disk so they can be easily accessed. When you are finished using the Bobcat, you should be sure to log out. Give the Emacs command esc-X logout. Emacs will check whether all editing buffers have been saved on the hard disk since the last time they were modified, and ask you if you want to save any buffers that need to need to be saved.

If you are sure a Bobcat is not being used, but it is not running the login loop, you should logout and login anew before using the system, because there is no way to know which variables have been defined or redefined in the environment.

1.3 Files and floppy disks

Your 6.003 package of notes should have included a 3\frac{1}{2}-inch floppy disk that you can use for saving individual files from one computer session to the next. When you log in, the files on your floppy disk are copied to a directory on the Bobcat hard disk. When you log out, this directory is copied back to your floppy disk, and the previous contents of the floppy disk are destroyed.

1.3.1 Disks and Files

Information in Unix is organized in terms of files, which are in turn grouped into directories. A file is a bunch of information that is stored together, and has associated with it a file name that must be unique on the directory. In general, a file is specified by a Unix path name, which is a sequence of directory names separated by slashes, ending in a file name.

For example, the path name /u/6003/files/ps1.scm specifies that the file named ps1.scm in the directory named files, which is itself a subdirectory of the directory named 6003, which is a subdirectory of u, which is a top-level Unix directory. When you log in, the system will copy the files from your floppy disk onto the directory /u/6003/files. When you log out, the files on this directory will be copied to your floppy disk.

In principle, you would need to specify the entire sequence of directory names in order to indicate a file. However, the system sets up a default prefix consisting of /u/6003/files. Whenever Emacs asks for a file name, it will print ~/files/, which stands for the default prefix, onto which you append your file name. Thus, to access the file /u/6003/files/ps1.scm you need only type ps1.scm after the ~/files/ printed by Emacs.

To access a file on some other directory, rub out the prefix and type any path name you choose. If you are a Unix hacker, you can explore to see how more general directory names are structured, but for 6.003 you need only (should only) work in the default directory.

1.3.2 Non-standard use of floppy disks

Files are automatically copied from and to your floppy disk when you log in and log out. The system also includes a few commands that give you additional control over floppy disks. You do not normally need to use these, but they may come in handy for making backups or for other purposes.

• The Emacs command esc-x save-floppy will save the contents of the /u/6003/files directory onto the floppy disk you specify. (Emacs will ask you which floppy disk you want to use—the one in the left or right drive.) This operation is automatically done when you log out, but you would use this command explicitly in order to make a backup copy. People make mistakes, especially at 3:00 AM while doing a homework assignment. For that matter, computers do too, occasionally scrambling a formerly fine file system. For this reason it is generally a good idea to periodically backup your files onto another disk. If you work regularly with a partner, you can use one of your floppy disks for backup.

• The command esc-x examine-floppy will show the names of files stored on a given floppy disk. Files are stored on the disk in nonstandard format, so you must load the disk into the files directory before you can actually use the files.

When someone logs out, or reloads the files directory from a floppy disk, the previous contents of the directory are temporarily saved. The directories /u/6003/files-1 through files-3 contain the three previous versions of the files directory. In case of some disaster (such as accidentally destroying the files directory by loading from a new disk) you may be able to recover by looking in these other directories. You should probably, however, ask a TA for help.

1.3.3 Initializing Disks

If the floppy disk has a format that is unrecognizable by the computer (for instance, if this is a disk that has never been used) the system will offer to initialize the disk for you. If you indicate that you want the disk to be initialized, the system will ask you to provide a name by which to identify the disk. The name is for your own use—to keep you from getting confused if you are using more than one disk. The case of the letters in the disk name is significant. Once initialization has begun, do not touch anything until the procedure has finished.

If a disk is already initialized and you want to re-initialize it for some reason, place the disk in one of the disk drives and execute the Emacs command esc-X initialize-floppy. you log in (section 1.2.) Remember: initializing a disk will destroy any information previously on the disk.

1.4 Hardcopy listings and screen images

There are two laser printers in the 6.003 lab. You can print a text file on by using the Emacs command esc-xprint-file followed by the file name. The Emacs command esc-xprint-screen will make the laser printer produce an image of everything on the screen, so you can get hardcopy of graphs and other graphics.

Do not use esc-x print-screen for printing text files. Instead, use the command esc-xprint-buffer. This is much faster than esc-X print-screen, since it transmits character codes rather than screen bit images, not to mention that it prints the entire buffer-not only the part that appears on the screen at the moment.

The Scheme user interface

This chapter provides details about using Scheme on the Bobcat system. It explains how to enter Scheme, how to evaluate expressions, how to create and edit program files, how test and debug programs, and how to obtain printed output. Chapter 6 of this manual gives a complete list of the primitive procedures and special forms included in the Scheme implementation.

2.1 Running Scheme

You run Scheme by first going through the login procedure as described in section 1.2. This will leave you in the Emacs editor, in a buffer named *scheme*. You create Scheme expressions by typing them or reading them from a file. You can evaluate an expression by giving the Emacs command ↑z, which evaluates the expression preceding the cursor. The result of the evaluation is displayed at the cursor position in the *scheme* buffer. The simplest way to use Scheme is to work in the *scheme* buffer and type input expressions, following each one by ↑z to have Scheme print its value. More generally, you can move around in the *scheme* buffer to re-evaluate or edit some previous expression. In general, ↑z will cause Scheme to evaluate the expression preceding the cursor. The command esc-z evaluates the current definition (i.e., the top-level definition that contains or precedes the cursor). The result will always be printed at the cursor position in the *scheme* buffer.

Helpful hint: When you are typing Scheme expressions, use ↑J rather than return to start a new line. ↑J both starts a new line and indents to the correct amount, as dictated by the parentheses in your expression. In this way, your programs remain much more readible, and it is easier to catch parentheses errors.

2.1.1 Indicators of Scheme’s status

Normally, Scheme is either running your program or running a system procedure known as the read-eval-print loop (or REP loop). When you first start Scheme, it will be running a “level 1” REP loop. The status of Scheme is indicated in the mode line for the *scheme* buffer.

For instance, the following mode line

    -----Emacs: *scheme*   I 1 [REP Loop]   (Scheme: run)----Bot--

shows that we are at the bottom of the *scheme* buffer, which is connected to a running Scheme. The character I indicates that Scheme is waiting for input. When Scheme is running, the I is replaced by an R, or by a G if Scheme is garbage collecting. You can continue to type at the editor while Scheme is running—this is a good way to confuse yourself. To keep the confusion from becoming hopeless, Emacs will not allow you to evaluate another Scheme expression until the previous evaluation is finished. The [REP Loop] in the mode line above indicates that Scheme is running its ordinary read-eval-print loop.

If evaluating an expression signals an error, Scheme ask you whether you want to abort from the error. Aborting will return you to the read-eval-print loop. If you do not choose to abort, Scheme will enter an error REP loop. The mode line indicator will change to [Error]. Scheme’s error REP loops provide some powerful facilities for debugging, which are described in chapter 5. To exit the error loop and return to the REP loop, type ↑c G (control-C followed by G).

The number 1 in the mode line above indicates that we are evaluating expressions at “level 1.” Other levels are used during debugging. If the level number gets higher than 1 and you are not (purposely) using the debugging system, then you are probably doing something wrong. (Most likely, you forgot to exit an error loop by typing ↑c G.) See chapter 5 for more information on read-eval-print levels and on the debugging system.

2.1.2 Evaluating expressions from other buffers

You can move the Emacs cursor and select for evaluation any expression, either in the *scheme* buffer or in some other buffer. You can also use Emacs to mark a region and evaluate the entire region using the Emacs command esc-↑Z. You can also evaluate an entire buffer using the esc-O command. As the expressions are evaluated, the values returned are shown in the echo area at the bottom of the screen, and also placed at the end of the

*scheme* buffer.

2.2 Multiple buffers and windows

If you are working with more than a small amount of code, you will probably want to compose your programs in one buffer, rather than to intermix your program text with Scheme output, as in the *scheme* buffer. In general, you will find it convenient to work with two text buffers—one for the file you are editing, and the *scheme* buffer for Scheme interactions. You compose and edit procedures in the file buffer. Once you have typed a procedure definition (most likely a Scheme define expression), you can transmit the definition to Scheme by evaluating it with esc-z. Then you can move to the *scheme* buffer to try the procedure.

In addition to the *scheme* buffer, the Scheme system automatically creates a buffer called *default-edit*, which you can use for editing definitions that are not associated with any file. Loading a file into this buffer will change the name of the buffer to the name of the file you select.

2.2.1 Windows and screen configurations

Figure 2.2.1 shows the screen configured with two windows—one for the *scheme* buffer and one for an edit window containing definitions that will be saved in a file. You would normally use this configuration when you are writing and incrementally testing programs. When there is more than one window, you can use the Emacs command ↑x O to switch between windows. (That’s the letter “oh”, not the number zero.)

Figure 2.1 shows the screen configured as a window for the *scheme* buffer and a window for graphics. You would normally use this configuration for running Scheme programs that draw graphs. Graphics is drawn in a region of the screen allocated to a graphics buffer, in which you cannot type. The Emacs command esc-↑L clears the entire screen, including the graphics. It will redisplay the text region of the screen, but not the graphics.

Figure 2.2.1 shows the screen configured as three windows—one for the *scheme* buffer, one for graphics and one for a file. You would normally use this configuration to confuse yourself and to impress your parents.

16 CHAPTER 2. THE SCHEME USER INTERFACE

Figure 2.1: The screen configured using esc-x window-scheme-edit. Figure 2.2: The screen configured using esc-x window-scheme-graphics.

Figure 2.3: The screen configured using esc-x window-all.

To set up the various screen configurations, you use the following Emacs extended commands:

esc-x window-scheme Configure the screen with one window, with the *scheme* buffer.

esc-x window-edit Configure the screen with one window for editing.

esc-x window-scheme-graphics Configure the screen with two windows— one for *scheme* and one for graphics.

esc-x window-scheme-edit Configure the screen with two windows—one for *scheme* and one for editing.

esc-x window-all Configure the screen with three windows—for *scheme*, for graphics, and for editing.

In all of the cases above, “a window for editing” will view the buffer that you most recently visited (either by reading in a file using the Emacs command ↑x↑f or by selecting the buffer using ↑x b).

2.3 Using Program Files

To process a file of Scheme programs, you can load the file into an Emacs buffer using the Emacs command ↑X↑F. Then you can evaluate the buffer with the esc-O command. (That’s the letter “oh”, not the number zero.)

Alternatively, if you do not want to look at or edit the contents of the file, you can load the file directly into Scheme using the Scheme load procedure. For example, evaluating the expression

    (load "ps1.scm")

will load the file ps1.scm from the default directory.

2.3.1 Loading Problem Set Files

Most of your time in the laboratory will probably be spent working on assigned problem sets. Problem sets are distributed in printed form during lecture, and you should read and understand these handouts before coming into the laboratory to work on them. Some of the problem sets will include one or more program files to work with on the Bobcat. The Emacs command esc-X load-problem-set will help you load a problem set. Emacs will ask for the number of the problem set. Depending on the problem set, Emacs may try to load code directly into Scheme, write files onto your disk, or both. The problem set handout that instructs you to use the command will tell you what files should be loaded or written in each case.

2.4 Printing Transcripts of Scheme Sessions

One easy way to get a printed copy of a Scheme session is to save the *scheme* buffer as a file, and then use the Emacs command esc-xprint-file, which prints a file on the laser printer in the 6.003 lab. You can also edit the *scheme* buffer, move portions of it to another buffer, and save and print that.

Another way to make a transcript is to use the Scheme procedures

transcript-on and transcript-off. Transcript-on takes a file name

as argument and causes all subsequent input and output to be recorded in a file. Transcript-off stops the recording. After making the transcript you can edit and/or print the file. However, given the presence of the Emacs *scheme* buffer, you probably will not need to use the two transcript commands.

The 6.003 Toolbox

The Toolbox is a collection of Scheme procedures that are useful for system and signal analysis. These procedures are automatically loaded when you start Scheme on a 6.003 Bobcat. Included are procedures for defining complex numbers and a variety of functions of complex numbers, procedures for carrying out generic operations on combinations of real or complex numbers or functions that return real or complex values, and procedures for manipulating polynomials and rational functions—including procedures for finding polynomial roots and partial-fraction expansions. Please tell us about any bugs you find, as well as suggestions for additions and improvements.

3.1 Complex numbers and operators

The 6.003 Toolbox extends the ordinary Scheme arithmetic operations to work on complex numbers. For example, you can use the + operator to add 3+2j and 1.5-3j to obtain 4.5-1j. You can also perform arithmetic on operators. An operators is a numeric function of a numeric argument. For example, you can use Scheme + operations to add the operator 2s + 3 to s^{2} − 1, obtaining the operator s^{2} + 2s + 2.

3.1.1 Complex numbers

Complex numbers can be created using the procedure make-rectangular, which returns a complex number with a specified real and imaginary part. You can also create a complex number using make-polar, which returns the complex number with a specified magnitude and angle. Complex numbers are printed by Scheme in the form a+bj where a and b are ordinary numbers. Scheme’s arithmetic operators work on complex numbers and on combinations of real and complex numbers. Here are some examples:

    (make-rectangular 3 4)  ⟹ 3+4j
    (- 6 (make-rectangular 3 4))⟹ 3-4j
    (/ 2 (make-rectangular 3 4))⟹ .24-.32j
    (* 3 (make-rectangular 3 4)
         (make-rectangular 5 6))⟹ -27+114j
    (abs (make-rectangular 3 4))⟹ 5
    (make-polar (sqrt 2)
                (/ pi 4))  ⟹ 1.+1j
    (sqrt -5)  ⟹ 0+2.2360679775j

Section 6.8 provides a complete list of Scheme’s numerical procedures.

3.1.2 Operators

An operator is a Scheme object that represents a (real or complex-valued) numerical function of a single (real or complex) number. There is essentially no difference between an operator and the single-argument procedure that it specifies—and Scheme provides operations for converting between single-argument procedures and operators, and for evaluating an operator at a specified value. However, operators and procedures are maintained as distinct types of objects for clarity in programming.

Operators can be created by transforming a single-argument procedure into an operator using procedure->operator, or by combining other operators using Scheme’s arithmetic operations. For example, if s is the identity operator (i.e., the value of s at any number is the number itself) then (* s s) is the operator whose value at any number is the square of that number.

(operator? obj )  procedure

Returns #t if obj is an operator.

(operator-value operator z)  procedure

Returns the value of the operator when applied to the specified number.

Note: If applying the operator to the value produces an arithmetic overflow error (such as division by zero) operator-value will choose a slightly different value for the argument and return the result at this new value. For instance, if the operator represents a rational function, and you ask for its value at a pole, you will obtain a large answer, but there will be no arithmetic overflow.

s  variable

This is a predefined name for the identity operator.

For most 6.003 applications, s is the only primitive operator you need worry about—all other operators you are likely to run across will be created by starting with s and applying numerical operations. Scheme’s numerical procedures work on operators to produce new operators. In general, a procedure P applied to operators O_{1},… O_{n} produces the operator whose value at a number z is P applied to O_{1}(z),… O_{n}(z). Here are some examples:

    (operator-value s 27)  ⟹ 27
    (operator-value (+ 1 (* s s)) 5)
                                ⟹ 26
    (define (f x) (/ (+ x 1) (- (* x x) 1)))
    (define h (f s))
    (operator-value h (make-rectangular 0 1))
                                ⟹ -.5-.5j
    (define m (+ (* (sin s) (sin s)) (* (cos s) (cos s))))
    (operator-value m .3)  ⟹ 1
    (operator-value (+ s m) 10) ⟹ 11

(procedure->operator proc)  procedure

Proc should be a procedure of one argument. Returns the operator whose value at any x is obtained by applying the procedure to x. You can use this to create primitive operators other than s.

(operator->procedure operator)  procedure

Returns a procedure of one argument that performs the computation specified by the operator. In 6.003 you will normally keep things in operator form, so that you will probably not use operator->procedure.

3.2 Polynomials

A polynomial is represented by a list of (possibly complex) term coefficients in ascending order of term powers, i.e., a_{0} + a_{1}s + a_{2}s^{2} + ⋯ + a_{n}s^{n} is represented as the list (a_{0} a_{1} a_{2} ⋯ a_{n}). You should get used to typing in polynomials in this list notation. The following display-poly procedure is useful for checking what you type.

(display-poly p)  procedure

    (display-poly '(2 -1 3))  ⟹ unspecified
    ;;computer prints 3x^{2} − x + 2

Display-poly also displays rational functions: Given a list of two polynomials p_{1} and p_{2}, display-poly will display p_{1}/p_{2}. Given a list of three polynomials p_{1}, p_{2}, p_{3}, display-poly will display p_{1} + (p_{2}/p_{3}).

Note: Display-poly only shows things on the screen—it does not return a value that you can use in subsequent computations.

(add-poly p_{1} p_{2})  procedure

Returns the polynomial that is the sum of the polynomials, p_{1} + p_{2}.

    (add-poly '(1 3 7 6)
              '(2 -1 3))  ⟹ (3 2 10 6)

(sub-poly p_{1} p_{2})  procedure

Returns the polynomial that is the difference of the polynomials, p_{1} −p_{2}.

Note: Calling sub-poly with a single argument leads to an error.

    (sub-poly '(1 3 7 6)
              '(2 -1 3))  ⟹ (-1 4 4 6)
    (sub-poly '(1 3 7 6))  ⟹ error
    (sub-poly '() '(1 3 7 6)) ⟹ (-1 -3 -7 -6)

(mul-poly p_{1} p_{2})  procedure

Returns the polynomial that is the product of the polynomials, p_{1}p_{2}.

    (mul-poly '(1 3 7 6)
              '(2 -1 3))  ⟹ (2 5 14 14 15 18)

(div-poly p_{1} p_{2})  procedure

Returns a list of two polynomials, the quotient and the remainder. If the degree of the numerator of p_{1} is less than the degree of the denominator p_{2}, the quotient is the empty list.

    (div-poly '(1 3 7 6)
              '(2 -1 3))  ⟹ ((3 2) (-5 2))

corresponding to

\frac{1 + 3x + 7x^{2} + 6x^{3}}{2 − x + 3x^{2}} = 3 + 2x + \frac{−5 + 2x}{2 − x + 3x^{2}}

(scale-poly factor poly)  procedure

Returns the polynomial whose coefficients are the coefficients of poly multiplied by factor.

    (scale-poly 2 '(1 3 7 6)) ⟹ (2 6 14 12)

(poly->roots poly)  procedure

(poly->roots poly initial-guess)  procedure

Returns a list of the roots of poly. The second argument, which is optional, is the initial guess for the Newton iteration. If omitted, the default value is 0.1 + j.

    (poly->roots '(2 4 3 1))  ⟹ (-1+1j -1 -1-1j)

(roots->poly root-list)  procedure

Returns the polynomial whose roots are in root-list.

    (roots->poly
     (list (make-rectangular -1 1)
           -1
           (make-rectangular -1 -1)))
                                ⟹ (2 4 3 1)

(poly->proc poly)  procedure

Returns a procedure whose value for any argument is the value of the polynomial represented by poly evaluated at that argument.

    (define bar
      (poly->proc '(2 2 1)))  ⟹ unspecified
    ;;the polynomial specified by the list is 2 + 2x + x^{2}

(bar -1) ⟹ 1 ;2 + 2(−1) + (−1)^{2} = 1

    (bar (make-rectangular -1 1)) ⟹ 0

3.3 Rational Functions

A rational function is the ratio of a numerator polynomial and a denominator polynomial. It can also be represented in the form of a partial fraction expansion, from which it is easy to derive the time function whose Laplace transform is the rational function. The following procedures evaluate the relationships among these various attributes of rational functions.

(operator->rat-func operator order)  procedure

Given an operator and an order n, this procedure attempts to express the operator as a rational function whose numerator has degree n − 1 and whose denominator has degree n. The procedure returns the the numerator and denominator polynomials as lists of coefficients. For example, the list ((a0 a1 a2) (b0 b1 b2 b3)) corresponds to the rational function of 3rd order

\frac{a_{2}s^{2} + a_{1}s + a_{0}}{b_{3}s^{3} + b_{2}s^{2} + b_{1}s + b_{0}}

The result is normalized so that the highest-order coefficient of the denominator is equal to 1. If the value of n supplied is smaller than necessary, the procedure will signal the error that n is too small. If the value of n supplied is larger than necessary, the procedure will work, although larger values of n will require longer computation time, and, due to roundoff error, the procedure may find spurious high-order coefficients.

    (define n (+ (* 2 s) 3))
    (define d (+ (* 4 s s) 5))
    (operator->rat-func (/ n d) 2)
                                ⟹ ((.75 .5) (1.25 0 1))
    (operator->rat-func (/ n d) 3)
                                ⟹ ((.75 .5) (1.25 0 1))
    ;;the second one takes longer
    (operator->rat-func (/ d n) 2)
    ;;error -- n is too small: 2
    (operator->rat-func (/ d n) 3)
                                ⟹ ((2.5 0 2.) (1.5 1))

(rat-func->pfe numer-poly poles)  procedure

This procedure creates a partial fraction expansion of a rational function, given the poles. The procedure is based on the idea of subtracting out pole terms one by one and expanding the remainder.

\frac{N(s)}{(s − s_{0})D(s)} = \frac{N(s_{0})/D(s_{0})}{(s − s_{0})^{n}} + \frac{\frac{N(s)−(N(s_{0})/D(s_{0}))D(s)}{s−s_{0}}}{(s − s_{0})^{n−1}D(s)}

As an example, consider

\frac{2s^{5} + 9s^{4} − s^{3} − 26s^{2} + 5s − 1}{(s + 1)^{2}(s − 1)^{3}(s + 2)} = \frac{3}{(s + 1)^{2}} \frac{−2}{s + 1} \frac{−1}{(s − 1)^{3}} \frac{1}{(s − 1)^{2}} \frac{3}{s − 1} \frac{1}{s + 2}

    (rat-func->pfe '(-1 5 -26 -1 9 2) '(-1 -1 1 1 1 -2))
                                ⟹ ((3 -2 -1 1 3 1) (-1 -1 1 1 1 -2))

Numer-poly is entered as a list of coefficients in order of ascending powers of terms. Poles is a list of roots of the denominator polynomial; repeated roots must be clustered together and roots should be listed in order of increasing magnitude. Note that the coefficient of the highest-order power in the denominator polynomial is implicitly assumed to be unity. The result returned by rat-func->pfe is a list of two lists. The first list is called the residues list (although strictly-speaking only the coefficients of 1st-order terms are properly called residues); the second is the list of poles . The order of the terms in the residues list is the same as the poles list; for repeated roots, terms are listed in decreasing order of the pole.

(pfe->rat-func residues poles)  procedure

This procedure reconstructs a rational function as a list of two terms in the form (numer-poly poles) from a partial fraction expansion described by a residues list and a poles list.

    (pfe->rat-func '(3 -2 -1 1 3 1) '(-1 -1 1 1 1 -2))
                                ⟹ ((-1 5 -26 -1 9 2) (-1 -1 1 1 1 -2))

(pfe->time residues poles)  procedure

This procedure returns an operator whose value is the inverse Laplace transform of the rational function of complex frequency described by the residues list and the poles list. For example, the rational function with unity residues and poles at ±j is 2s/(s^{2} + 1) and (from tables) has inverse Laplace transform 2 cos tu(t):

    (define t-func
      (pfe->time
       '(1 1)
       (list (make-rectangular 0 1)
             (make-rectangular 0 -1))))
    (operator-value t-func (/ pi 3)) ⟹ 1
    (operator-value t-func (/ (- pi) 3)) ⟹ 0

3.4 Plotting

The system can draw graphs of frequency responses on a linear or logarithmic scale. The graphs are drawn in various graphics fields whose arrangement is controlled by set-fields!. Graphed values are memoized as they are drawn, so that if you plot a graph and then clear the screen, the graph can be redrawn quickly.

(plot-f-resp op df ymax field-number)  procedure

This plots the values of the operator op, for a sequence of values of frequency s. The frequency increment is df. The function is plotted for values of s = 0, jdf, 2jdf,…, 128jdf. Ymax is the largest value of the magnitude of the function over the range. Field-number specifies the graphics field in which the plot is displayed (see set-fields! below). Plot-f-resp creates two graphs—one for the magnitude with range 0 through ymax, and one for the phase with range −π through π.

(bode-plot op fmin ymax field-number)  procedure

Op is an operator. Frequency is the starting frequency. Makes a loglog plot of the magnitude (in decibels) of op over the range log_{10} s = 0 + j log_{10} fmin through log_{10} s = 0 + j(7 + log_{10} fmin). Ymax is the maximum (in decibels) of the magnitude—the decibels are scaled from ymax − 100 through ymax. Also plots the phase on a scale −π to π. Field-number specifies the graphics field in which the plot is displayed (see set-fields! below).

(set-fields! horiz vert)  procedure

Controls the configuration of graphics fields on the screen. Set-fields configures the screen so that there are vert rows, each containing horiz graphics fields. The fields will be numbered starting at the upper left and going across the first row, then to the left of the second row, and so on. When Scheme is started, the default is two rows of two fields.

(list-graphs)  procedure

Graphed values are saved when they are drawn. List-graphs returns an index to the graphs currently stored, containing a graph number, a description (such as “Magnitude of Bode Plot”) and a field number. See regraph

and remove-graph.

(regraph)  procedure

(regraph n_{1} n_{2} …)  procedure

Redraws stored graphs. With no arguments, redraws all the graphs in the list shown by list-graphs. Arguments n_{i} specify particular graphs to be redrawn. Positive values refer to the numbers in the list shown by list-graphs; negative values count back from the current graph, e.g., −1 refers to the previous graph drawn.

(remove-graph n_{1} n_{2} …)  procedure

Removes the graphs numbered n_{1}, n_{2},… from the list of graphs (see list-graphs). You should do this to reclaim storage after you have drawn many graphs. Negative values for the n_{i} count back from the current graph, e.g., −1 refers to the last graph drawn.

3.5 Other definitions

For convenience, the following symbols are defined.

pi  variable
2pi  variable

Variables whose values are (approximations to) π and 2π respectively.

j  variable
-j  variable

These variables, representing ±\sqrt{−1} are equal to (make-rectangular 0

1) and (make-rectangular 0 -1) respectively.

The Emacs editor

Almost all of your interaction with the Bobcat Scheme system will be via typing at the Emacs text editor. The Emacs editor was originally designed and implemented in the 1970s at MIT by Richard Stallman and it has been widely copied and reimplemented for many machines. The Emacs used in 6.003 is GNU Emacs, which is a free version of Emacs distributed by Stallman and the Free Software Foundation.^{1} GNU Emacs for 6.003 is similar to the NMODE editor used in 6.001 and is (hopefully) identical to the version of GNU Emacs used on Project Athena workstations.

Emacs is a sophisticated and extensive editor, with many commands. This manual provides only very sparse documentation because good Emacs documentation is readily available elsewhere and Emacs contains extensive on-line documentation and help facilities.^{2}

• The GNU Emacs Manual by Richard Stallman provides a complete description of GNU Emacs. The manual can be purchased from MIT Information Services in Room 11-209.

• The Emacs command ↑h I will run the INFO documentation reader.

1Free means that everyone is free to use GNU Emacs and free to redistribute it on a free basis. The Free Software Foundation is a non-profit, tax-exempt organization dedicated to the development and support of high-quality free software. For more information on free software, read the GNU Manifesto. This is included in the GNU Emacs Manual [4] and can be read on-line at a 6.003 computer using the INFO documentation reader.

2For 6.003, we have made some customizations to GNU Emacs for running Scheme.

These are not included in the GNU Emacs Manual or in the on-line INFO documentation.

These commands include the extended commands mentioned throughout this manual and also Scheme evaluation commands described below in section 4.11.

This includes the GNU Manifesto and all of the GNU Emacs Manual in on-line form.

• If you have never used Emacs, the command ↑h T will run an on-line Emacs tutorial.

• The Emacs command ↑h ? will show you a list of help commands included in Emacs.

• When you are typing an Emacs extended command (using esc-X), typing a question mark at any point will show you all the commands that begin with the characters you have typed.

The command summary in this chapter is adapted from the GNU Emacs Reference Card originally designed by Neal Ziring of Washington Univ. Copies of the card are included in the GNU Emacs Manual and can be purchased separately from Information Services.

4.1 Basic Emacs concepts

Insertion You are always in insert mode in Emacs. Ordinary text is inserted as it is typed.

Commands Emacs commands are invoked by typing sequences of control characters. Control chars are written ↑char, escape sequences esc-char.

Extended commands These commands are named by text strings. To invoke an extended command, type esc-X followed by the command name. Your typing will appear at the bottom of the screen in the echo area.

Buffer A block of text that you may examine and modify in the editor.

Window An area on the screen. A buffer can be displayed in one or more windows.

File A block of text that can be read into a buffer or written from a buffer.

Kills Text that is killed is placed in a special kill-buffer. Killed text can be retrieved with a yank. The most recent sixteen kills are kept in the kill-ring.

Point The current cursor location in each buffer is called point.

Mark The mark is an invisible pointer in each buffer. It is set by many commands to the location where they were performed.

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

Registers Emacs has 26 general registers, named a through z. Registers may hold commands, locations, numbers, or text.

Modes Every buffer has a major mode, and maybe some minor modes. Major modes determine language-sensitive behavior and define special mode commands. Minor modes add special features without adding new commands.

4.2 Getting help

esc-? Invoke the self-documenter. The self-documenter function will prompt for a help command. Most help commands ask for a name or character, which they will then describe for you.

↑h a document commands apropos a word
↑h b list all key bindings
↑h c describe a key sequence briefly
↑h f describe a function
↑h k describe a key sequence completely
↑h l show last 100 characters typed
↑h m describe this major mode
↑h v describe a variable
↑h ? show list of help commands
↑h t visit a friendly Emacs tutorial
↑h i invoke Info documentation reader

4.3 The display

Text Area A view onto a text buffer. Each window has its own text area. Your display always has at least one text area on it.

Mode Line Status line displayed at the bottom of a window. The mode line displays the current buffer name, major and minor editing modes, and current location in the file. The variable mode-line-format defines the contents and layout of the mode line.

Echo Area A one-line area at the bottom of the screen. Error messages and progress messages are displayed in the echo area. This area is also called the mini-buffer, because Emacs command prompts and your responses are typed there.

4.4 Simple motion

↑a  beginning-of-line
↑b  backward-char
↑e  end-of-line
↑f  forward-char
tab  indent-for-tab-command
return  newline
↑j  newline-and-indent
↑n  next-line
↑o  open-line
↑p  previous-line
backspace delete-backward-char
esc-<  beginning-of-buffer
esc->  end-of-buffer

4.5 Scrolling

↑v  scroll-up
↑x < scroll-left
↑x > scroll-right
esc-↑v scroll-other-window
esc-v scroll-down

4.6 Text motion

↑x [ backward-page
↑x ] forward-page
esc-[ backward-paragraph
esc-] forward-paragraph
esc-a backward-sentence
esc-b backward-word
esc-e forward-sentence
esc-f forward-word

4.7 Transposition

↑t  transpose-chars
↑x↑t transpose-lines
esc-t transpose-words

4.8 Queries and fixes

↑g  quit immediately
↑l  recenter (and fix screen)
esc-↑l recenter and clear graphics
↑h  help-command
↑q  quoted-insert
↑x = what-cursor-position
↑x l count-lines-page
↑x u undo previous command
↑]  abort-recursive-edit
esc-= count-lines-region

4.8.1 Query replace

esc-% Invoke interactive replacement. Query-replace will prompt you for a string and another string with which to replace it. Replacement proceeds from the current location (point) to the end of the buffer.

The following query responses are recognized.

space  replace this match
backspace skip to next match
esc  exit query replace
.  replace this match and exit
↑r  enter recursive edit
↑w  delete match and recursive edit
!  replace all remaining matches
^move back to previous match

4.9 Deletes, kills, and yanks

↑d  delete-char
↑k  kill-line
↑w  kill-region
↑y  yank
backspace  delete-backward-char
↑x↑o  delete-blank-lines
↑x backspace backward-kill-sentence
esc-↑w  append-next-kill
esc-\  delete-horizontal-space
esc-^delete-indentation
esc-d  kill-word
esc-k  kill-sentence
esc-w  copy-region-as-kill
esc-y  yank-pop
esc-backspace backward-kill-word

4.10 Manipulating Scheme expressions

The term sexp stands for symbolic expression. This refers to a Lisp “unit” such as an atom or a list. Thus, “forward-sexp” will move past the next symbol if the cursor is at the beginning of a symbol, and move to after the matching close parenthesis if the cursor is at an open parenthesis.

4.11. EVALUATING SCHEME EXPRESSIONS 35

esc-↑a beginning-of-definition
esc-↑b backward-sexp
esc-↑e end-of-definition
esc-↑f forward-sexp
esc-↑k kill-sexp
esc-↑t transpose-sexps
esc-( insert-parentheses
esc-) move-past-close-and-reindent

4.11 Evaluating Scheme expressions

↑c g stop evaluating
↑z  evaluate expression preceding cursor
esc-z evaluate current definition
esc-↑z evaluate region
esc-o evaluate buffer

4.12 Buffers

↑x↑b list-buffers
↑x↑f find-file
↑x↑s save-buffer
↑x a append-to-buffer
↑x b switch-to-buffer
↑x h mark-whole-buffer
↑x k kill-buffer
↑x n narrow-to-region
↑x s save-some-buffers
↑x w widen
esc-~ mark buffer as not-modified

4.13 Windows

The extended commands for configuring the screen are described in section 2.2.1. In addition, Emacs has the following commands:

↑x o move to other-window
esc-↑v scroll-other-window

36 CHAPTER 4. THE EMACS EDITOR

4.14 Files

↑x↑f find-file
↑x↑r find-file-read-only
↑x↑v find-alternate-file
↑x↑w write-file
↑x i insert-file

4.15 Searching

↑s  isearch-forward ↑r  isearch-backward esc-% query-replace esc-↑s isearch-forward-regexp To terminate a search, press the esc key.

4.16 Case changes

↑x↑l downcase-region
↑x↑u upcase-region
esc-c capitalize-word
esc-l downcase-word
esc-u upcase-word

4.17 Filling and centering

↑x f set-fill-column
↑x . set-fill-prefix
esc-q fill-paragraph

4.18. MARKS AND REGISTERS 37

4.18 Marks and registers

↑@  set-mark
esc-\ set-mark (same as ↑@)
↑x↑p mark-page
↑x↑x exchange-point-and-mark
↑x / point-to-register
↑x g insert-register
↑x h mark-whole-buffer
↑x j register-to-point
↑x r copy-rectangle-to-register
↑x x copy-to-register
esc-↑h mark-definition
esc-@ mark-word

4.19 Macros and repetition

↑u  universal-argument
↑x (  start-kbd-macro
↑x )  end-kbd-macro
↑x e  call-last-kbd-macro
↑x q  kbd-macro-query
esc--  negative-argument
esc-0… esc-9 digit-argument

4.20 Subsystems

↑x d dired (edit directory)

4.21 Exiting

esc-↑c exit-recursive-edit (such as ↑r from query replace)

4.22 Some Editing Modes

Invoke these as extended commands using esc-X. Use the on-line documentation to learn about these and other Emacs modes.

   scheme-mode               text-mode

38 CHAPTER 4. THE EMACS EDITOR

abbrev-mode               auto-fill-mode
fundamental-mode          overwrite-mode

Debugging

It will become apparent to you many times during a program’s evolution that the program is not entirely right. Instead of blaming the program for these faults, strange creatures called bugs are blamed. In this way, the programmer remains free of guilt. Errors and incorrect results are sure signs that bugs lurk inside a program, for the bugs cause the aberrant behavior.

Debugging usually depends on empirical testing, thus it can serve to reinforce the programmer’s belief in the correctness of his program, and it can aid in correction of a program which is not behaving as expected, but it cannot prove that the program is correct. If the program succeeds during debugging, there may be some yet-to-be-uncovered bug lurking within, waiting to show itself in some later run. The best protection against program bugs is a program that is well thought out and clearly set down in code.

Scheme provides several features to aid in debugging programs. Among these are the ability to trace the execution of a procedure, the ability to examine the current environment, and the ability to set breakpoints. From a breakpoint, you can examine the recent process history of your program.

Bugs are sometimes detected by the occurrence of an error while the program is running. When Scheme encounters an error, execution is abruptly halted, you are notified, and you are given thechoice of either aborting from the error, or entering an error read-eval-print-loop. (See section 5.1). Here is a typical error response:

    (+ 1 'a)
    Illegal datum in second argument position A
    Within procedure #[PRIMITIVE PROCEDURE &+]
    There is no environment available;

    using the current read-eval-print environment.

The error message—a concise description of the error—is the first thing printed. In this case, the error was a bad argument: the symbol a to the + procedure.

The error message is sometimes followed by information about the environment in which the error occurred. This is useful because the debugger includes some advanced features that allow you to probe or modify the environment. (See sections 5.4 and 5.5.) Sometimes, as in the example above, the system will tell you that no environment was found at all, which means that you are in the environment of the previous REP loop.

If you choose not to abort, the mode line information (indicating Scheme’s status) will change from

    I 1 [REP Loop]

to

    I 2 [Error]

to indicate that you are in an error REP loop. The number 2 signals that this REP loop is subordinate to a level 1 (top level) REP loop. See sections 5.1 and 5.2 for information on REP loops.

If you do choose to abort, you will return to the previous REP loop and you can try another expression. Beginning programmers have a tendency to automatically abort as soon as an error is encountered.^{1} This is unfortunate, because it destroys information about the error that can be used to aid in debugging. When you encounter an error, take some time to think about the error, rather than immediately aborting as a “knee-jerk” reaction.

Scheme provides system features that make use of the error environment in order to help you to try and locate where the error occurred. That is, you can see what expressions were being executed at the time of the error. The environment and history examiners, where and debug, respectively, are used for this. Of course, much can be determined about the state of the system at the time of the error by simply examining the values of variables in the error environment.

1This is similar to the behavior of children writing or drawing, who will ordinary crumple up the paper and start over again as soon as they make a mistake. Presumably, the error triggers some kind of “abort” reaction whose goal is to return the cognitive process to a simple known state as rapidly as possible. One of the useful things we can learn from programming is the possibility of debugging to correct our mistakes.

The program may run without error, but the result produced may be preposterous—another indication of bugs. For instance,

    (prime? 7)  ⟹ #f

In this situation, Scheme offers no clue as to the location of the bug—you’re on your own. You might produce a theory about the cause of the deviant behavior and then test it using the trace facility. You can also edit the program to insert checks and traces.

Debugging, like programming, is an acquired skill and an art. The tools available to you are described in the sections below. Use them creatively. The laboratory assistants are there to help you. Feel free to ask them for help.

5.1 Read-Eval-Print Levels

The Scheme interpreter works by running a read-eval-print loop (or REP loop). This means that expressions are read, evaluated, and the result of the evaluation is printed on the console. A REP loop can be nested inside another REP loop. This is what happens at a breakpoint or an error. The mode line indicator is changed to Break or Error to signify that another nested REP loop has been entered. The Emacs commands ↑c G, ↑c U, and ↑c X all affect the REP level you are at. The Level is the degree of nesting of REP loops, where level 1 is the topmost REP loop. Below are listed some control characters used to interrupt programs on various levels, also listed are other useful control characters.

↑c B Enters a Breakpoint. The new level will be one higher than it was before the breakpoint.

↑c G Halts execution at all levels. Returns to the top level (level 1) REP loop.

↑c U Halts execution locally. Returns to the previous REP loop, unless already at the top level loop. That is, the new level is one less than it used to be, unless you were already at level 1.

↑c X Halts execution locally. Returns to the current REP loop. The level number remains unchanged.

Once again, the different mode line indicators are: REP, ordinary readeval-print loop; Break, a breakpoint REP loop; and Error an error REP loop.

5.2 Breakpoint and Error REP Loops

As mentioned above, you can choose to enter an error REP loop whenever an error is signalled. This error may have been signalled internally by Scheme, or it may have been signalled by an error statement that you inserted in the program yourself. Loops of a slightly different flavor can be entered via the bkpt special form or by typing a ↑c B at the keyboard.

The Scheme breakpoint facility allows you to pause execution of a program in midstream, whereupon you can examine and modify the values of local variables, among other things. When you pause execution and enter a breakpoint, Scheme runs a REP loop just as it normally does—you type expressions and the interpreter evaluates them and prints their value. The difference is that the environment in which these expressions are evaluated is not the global environment, but rather the environment from which the breakpoint was entered.

Breakpoints can be entered in the following ways:

• Typing ↑c B at the keyboard. This will always leave you in the environment of the previous (lower level number) REP loop.

• Executing a procedure that had a breakpoint installed via one of the

     commands break, break-entry, break-exit, or break-both. This

will leave you in the environment created to evaluate the body of the “broken” procedure.

• Executing the procedure bkpt. This will leave you in the environment in which the bkpt is evaluated.

• Encountering an error. You are left in the environment in which the expression causing the error was evaluated. Because the Scheme interpreter is optimized so that it saves only environments that are needed for subsequent evaluations, errors may occur when there is no environment at all. In this case a warning is printed and you are left in the environment of the previous (lower level number) REP loop.

To continue from a breakpoint, evaluate the expression (proceed). The interpreter will continue as though the breakpoint had not occurred. If the REP loop was entered because of a bkpt or error special form, evaluating (proceed expression) will evaluate the expression and return that value for the value of the special form.

If the REP loop was entered because of a break-entry or break-exit, (proceed expression) will evaluate expression and return that value in place of the value which would be calculated by the “broken” procedure. This is convenient if you realize that a procedure is calculating the wrong answer. You may want to quickly try out the rest of your program as though this procedure really worked. You can break-entry the questionable procedure, and then use (proceed expression) to simulate the way the procedure should work.

Instead of continuing the program by using proceed, you can type ↑c G which aborts execution and returns to the top-level REP loop. This is frequently done after “snooping around” to discover the problem: type ↑cG and try again. Similarly, ↑c U halts execution and returns to the preceding (lower level number) REP loop. ↑cX resumes the current REP loop. This is useful, for example, when you ask Scheme to pretty-print a long procedure and want to stop it in the middle of the printing and get back to the current REP loop prompt.

For REP loops caused by errors in Scheme primitives, evaluating (proceed) will simply call the primitive again. This is rarely what you want to do. You should investigate the problem, fix the program, and try it all over again.

5.3 Trace and Break

Scheme provides procedures that allow you to trace the execution of a program and set breakpoints in the program. A procedure can be traced on entry or on exit. In addition, a breakpoint can be set when the procedure is entered or exited. When the entry of a program is traced, the arguments passed to it are shown at each entry. When the exit of a program is traced the arguments passed and the result returned are shown at each exit. Here is an example. The indicators preceding the user’s input show the level and REP loop information that appears in the mode line at each point.

     [1 REP] (define (fact n)
               (cond ((zero? n) 1)
                     (else (* n (fact (-1+ n))))))
    FACT

44 CHAPTER 5. DEBUGGING

[1 REP] (trace-entry fact)
[1 REP] (trace-exit fact)
[1 REP] (fact 3)
Entering <#<COMPOUND-PROCEDURE FACT> 3>
Entering <#<COMPOUND-PROCEDURE FACT> 2>
Entering <#<COMPOUND-PROCEDURE FACT> 1>
Entering <#<COMPOUND-PROCEDURE FACT> 0>
1 <== <#<COMPOUND-PROCEDURE FACT> 0>
1 <== <#<COMPOUND-PROCEDURE FACT> 1>
2 <== <#<COMPOUND-PROCEDURE FACT> 2>
6 <== <#<COMPOUND-PROCEDURE FACT> 3>
6
[1 REP] (untrace fact)
[1 REP] (fact 3)
6
[1 REP] (break-exit fact)
[1 REP] (fact 2)
1 <== <#<COMPOUND-PROCEDURE FACT> 0>
Breakpoint on exit
[2 Break] (*args*)
(0)
[2 Break] (*result*)
1
[2 Break] (proceed -1)
-1 <== <#<COMPOUND-PROCEDURE FACT> 1>
Breakpoint! Level: 2
[2 Break] (proceed)
-2 <== <#<COMPOUND-PROCEDURE FACT> 2>
Breakpoint on exit
[2 Break] (proceed)

During the breakpoint inserted by break-exit, the procedures *proc*, *args*, and *result* can be called to see the “broken” procedure, the values of the arguments, and the computed result (available only during an exit break), respectively. Type (proceed) to proceed from the breakpoint and return the value shown by (*result*), or type (proceed expression) to return the value of expression. In the above example, we made (fact 0) return −1 instead of 1.

5.4 The Environment Examiner: Where

The where procedure provides a method of examining and modifying environments. Where is a procedure of 0 or 1 arguments that enters a readexecute command loop when called. Unlike a REP loop, this loop reads one letter and treats it as a command to be performed. Scheme will prompt for the one-character command at the bottom of the screen in the Emacs echo area. To give a command, just type the character—you needn’t press return.

If called with no arguments, where examines the current REP loop environment. The optional argument can be an environment or an object with an environment associated with it, such as a procedure. Below is an example of where being called at a breakpoint in a Scheme procedure. This illustrates some of the things which can be done with where.

While the where procedure is a very useful debugging aid, using it effectively requires a good understanding of Scheme’s environment structures. For this reason you may find it less confusing to use only the C command initially.

Here is a brief description of each where command.

? Prints a summary of the where command characters.

A (for all) Displays the bindings in all of the frames in the current environment chain.

C (for current) Displays the bindings in the current frame.

E (for eval) Enters a REP loop in the current environment.

N (for name) Shows the name of procedure that created current environment frame.

P (for parent) Moves up to the parent of the current environment frame, then does a C command.

Q (for quit) Exits where.

S (for son) Move to the son of the current environment frame. This undoes a P command.

V (for value) Evaluates one expression in the current frame and pretty-prints the result.

W (for where) Evaluate an expression in the current frame and call where on the result.

Here is an example of using where. The indicators at the left of the user input show the information that would appear in the buffer mode line, and in the prompts in the echo area:

     [1 REP] (define (one x y z)
               (define (two x y z)
                 (define (three x y z)
                   (bkpt "In procedure three environment"
                         (list x y z)))
                 (three 1 2 3))
               (two 4 5 6))
     ONE
     [1 REP] (one 'a 'b 'c)
     In procedure three environment (1 2 3)
     Breakpoint
     [2 Break] (where)
     Environment Inspector
     [3 Where] c
     Frame created by the procedure THREE.
     Depth (relative to starting frame): 0
     Has bindings:
     X = 1
     Y = 2
     Z = 3

The C command prints the variable bindings in the currently selected environment frame. Since the breakpoint occurred inside the execution of the procedure three, the current environment is the one resulting from the application of C to the arguments 1 2 3.

The P command moves to the frame in which three was defined. In this case the parent is the frame created by the application of the procedure two to the arguments 4 5 6.

     [3 Where] p
     Frame created by the procedure TWO.
     Depth (relative to starting frame): 1
     Has bindings:
     X = 4
     Y = 5
     Z = 6
     THREE = #<COMPOUND-PROCEDURE THREE>

     [3 Where] p
     Frame created by the procedure ONE.
     Depth (relative to starting frame): 2
     Has bindings:
     X = A
     Y = B
     Z = C
     TWO = #<COMPOUND-PROCEDURE TWO>

     [3 Where] p
     Frame created by a MAKE-PACKAGE special form.
     Depth (relative to starting frame): 3
     Has bindings:
     USER-INITIAL-ENVIRONMENT = #<ENVIRONMENT 13679124>
     ONE = #<COMPOUND-PROCEDURE ONE>

Here we have reached the user initial environment in which the top most procedure one was defined. That’s enough …

     [3 Where] q

and we are back in the REP loop where we started. We can continue the program by typing (proceed).

Notice that we could stop at any environment and create a REP loop in it by using the E command. This allows you, for example, to define missing variables when you encounter an unbound variable error. Similarly, you can use the V (one expression) command to evaluate a single expression in any of the frames in the environment chain.

5.5 The Scheme Debugger: Debug

A breakpoint will allow you only to examine local variables and to evaluate expressions at the breakpoint. Often, however, tracking down a bug will require a more extensive investigation of the circumstances surrounding the error. The Scheme debugger system provides additional capabilities to aid in debugging.

The history examiner, entered using the debug command, enables you to examine the history of execution of an expression. The environment of any procedure application may then be examined and the interrupted process may be continued from any of the displayed nodes of evaluation.

Calling the debug procedure from within a Scheme breakpoint enters a read-execute loop, which accepts single-character commands which enable you to move backwards and forwards in the history of the expressions which have been evaluated. You can also examine procedures and variables at the different evaluation levels. The prompt is Debug. Just as with where, Scheme prompts for the commands in the mode line at the bottom of the screen.

In order to make good use of the debugger, you must understand the concept of a reduction and a subproblem. The 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 involve a sequence of reductions. The best way to get a feeling for how reductions and subproblems work is to write some test expressions and play with them using the debug procedure.

Here is a summary of the debug commands.

? Prints a summary of the debug commands.

B (for back) Moves back to the “previous expression,” that was being processed. What this means is as follows: One goes backwards along the sequence of reductions that produced the current expression until reaching the subproblem that led to this chain of reductions. Then one moves “upward” in the tree of subproblems, until reaching the expression that was typed at the REP loop which initiated the whole process.

C (for current) Shows all the variable bindings in the environment in which the current subproblem was being evaluated.

D (for down) Moves down to a lower subproblem level. This is the subproblem which was evaluated after (in time) the current one.

E (for eval) Enters a REP loop in the environment in which the current subproblem was being evaluated.

F (for forward) Moves to the “next” expression after the current one. The order is (the opposite of) the one described for the B command.

G (for go) Goes to a particular subproblem and reduction level. Debug asks you for the numbers. Each expression has two numbers to indicate a subproblem and a reduction of that subproblem. Simplified (more reduced) expressions have lower reduction numbers. Lower level (smaller subproblem) expressions have lower subproblem numbers. Thus the current error expression is numbered (0, 0).

H (for history) Prints a summary of the entire history. This is like typing B repeatedly.

I (for information) Redisplays the error message.

L (for list current expression) Pretty-prints the current expression.

P (for procedure) Pretty-prints current procedure.

Q (for quit) Exits debug returning to the environment in which the error occurred, and at the expression which caused the error.

R (for reductions) Prints all the reductions of the current subproblem level.

S (for subproblem) Prints the current subproblem and reduction showing where in the evaluation history the user is.

U (for up) Moves up to the previous subproblem level. This is a subproblem which includes as one of its parts the current subproblem. It has a higher subproblem number.

V (for value) Asks for an expression and evaluates it in the environment in which the current subproblem was being evaluated.

W (for where) Enters where on the current environment

Z (for zap) Asks for an expression and evaluates it in the current environment. The value of the expression is used in place of the value the current subproblem would have returned, and execution is resumed from this point in the original evaluation.

For a first look at the debugger we will use several of the common commands just to see how they work. Here is a demonstration.

     [1 REP] (define (fact n)
               (if (zero? n)
                   l
                   (* n (fact (-1+ n)))))
     FACT
     [1 REP] (fact 3)
     Unbound Variable L
     Error!
     [2 Error] (debug)
     Subproblem Level: 0  Reduction Number: 0
     Expression:
     L
     within the procedure FACT.
     applied to (0)
     [3 Debug]

The application of the procedure fact caused an error. We then called the debugger, which printed the expression whose evaluation caused the error to occur. The “Subproblem Level” and the “Reduction Number” are ways of numbering expressions in the history. The procedure whose body is currently being evaluated, as well as the arguments passed to it are displayed. The debugger accepts one letter commands which can be listed by typing ?.

The factorial problem above has a simple typo; the letter L is used instead of the number 1 in the if form, resulting in an unbound variable error. The debugger indicates that the error occurred when fact was called with 0 as its argument.

Although the bug in this case is easy to spot, we can look through the evaluation history, to see how the evaluation proceeds. The command H lists a summary of the history.

     [3 Debug] h
     Sub Prb. Procedure Name    Expression
     0                  FACT    L
     0                  FACT    (IF (ZERO? N) L (* N (FACT (-1+ N))))
     0                  FACT    (FACT (-1+ N))
     1                  FACT    (* N (FACT (-1+ N)))
     2                  FACT    (* N (FACT (-1+ N)))
     3                  FACT    (* N (FACT (-1+ N)))
     4                          (PRINT (SCODE-EVAL SCODE USER-CURRENT-ENVI ...
     5                          (SEQUENCE (SETUP-HISTORY! MAX-SUBPROBLEMS  ...
     6                  LOOP    (LOOP (CATCH (LAMBDA (AGAIN) (FLUID-LET (( ...
     7           DRIVER-LOOP    (DRIVER-LOOP (CATCH (LAMBDA (QUIT) (SET! T ...
     8  STARTUP-TOP-LEVEL-DR... (SEQUENCE (CATCH (LAMBDA (CONT) (SET! TOP- ...
     [3 Debug]
    Quit! Level: 1

Lines 4 through 8 printed by the examiner are pieces of the Scheme REP loop implementation itself, and should be ignored.

The most common error that can be corrected easily from the debugger is an unbound variable error. In this case, there are two possibilities. If you forgot to define the variable you can use the B command to search back through the history until you find the place where the variable should have been defined. Then, use the E command to enter a REP loop, and define the variable.

5.6 An Extended Debugging Session

This section illustrates use of the Scheme debug procedure in an extended session. The first example is the buggy fact procedure that was used as an example in section 5.5 above. The sequence begins with the interaction already described in section 5.5.

[1 REP] (define (fact n)
      (if (zero? n)
          l
          (* n (fact (-1+ n)))))
FACT
[1 REP] (fact 3)
Unbound Variable L
Error!
[2 Error] (debug)
Subproblem Level: 0  Reduction Number: 0
Expression:
L
within the procedure FACT.
applied to (0)
[3 Debug] s
Subproblem Level: 0  Reduction Number: 0
Expression:
L
within Procedure FACT
applied to (0)

The command S displays the current subproblem. The command B moves backwards in time.

[3 Debug] b
Subproblem Level: 0  Reduction Number: 1
Expression:
(IF (ZERO? N) L (* N (FACT (-1+ N))))
within Procedure FACT
applied to (0)

5.6. AN EXTENDED DEBUGGING SESSION 53

[3 Debug] b
Subproblem Level: 0  Reduction Number: 2
Expression:
(FACT (-1+ N))
within Procedure FACT
applied to (1)
[3 Debug] b
Subproblem Level: 1  Reduction Number: 0
Expression:
(* N (FACT (-1+ N)))
within Procedure FACT
applied to (1)

The F command moves forward through reductions one at a time, in the opposite direction to B.

[3 Debug] f
Subproblem Level: 0  Reduction Number: 2
Expression:
(FACT (-1+ N))
within Procedure FACT
applied to (1)
[3 Debug] f
Subproblem Level: 0  Reduction Number: 1
Expression:
(IF (ZERO? N) L (* N (FACT (-1+ N))))
within Procedure FACT
applied to (0)
[3 Debug] f
Subproblem Level: 0  Reduction Number: 0
Expression:
L
within Procedure FACT
applied to (0)

We are now back at the subproblem level containing the offending expression. The variable L is unbound. The Z (for ZAP) command asks for an expression to evaluate and returns this value as the value of the current subproblem to the previous subproblem, that is, the containing subproblem. Here we wanted L to be 1.

[3 Debug] z
    Enter an expression to EVALUATE and CONTINUE with: 1
    That evaluates to:
    1
    Confirm: [Y or N] -> y
    6

And here is the correct result. Let’s look at another example:

[1 REP] (define (square-root x)
          (define (square-root-iter ans)
            (if (close? ans)
                ans
                (square-root-iter (average (/ x ans) ans))))
          (define (close? ans)(< (abs (- (* ans asn) x)) .0001))
          (square-root-iter 1))
SQUARE-ROOT
[1 REP] (square-root 4)
Unbound Variable ASN
Error! Level: 2
[2 Error] (debug)
Subproblem Level: 0  Reduction Number: 0
Expression:
ASN
within Procedure CLOSE?
applied to (1)
[3 Debug] b
Subproblem Level: 1  Reduction Number: 0
Expression:
(* ANS ASN)
within Procedure CLOSE?
applied to (1)
[3 Debug] b

Subproblem Level: 2  Reduction Number: 0
Expression:
(- (* ANS ASN) X)
within Procedure CLOSE?
applied to (1)
[3 Debug] b
Subproblem Level: 3  Reduction Number: 0
Expression:
(ABS (- (* ANS ASN) X))
within Procedure CLOSE?
applied to (1)
[3 Debug] b
Subproblem Level: 4  Reduction Number: 0
Expression:
(< (ABS (- (* ANS ASN) X)) .0001)
within Procedure CLOSE?
applied to (1)

Above is a square root program that is divided into sub-procedures. In the program there is a bug. The debugger was called to reveal that the unbound variable ASN is in the expression (* ans asn) in the procedure CLOSE?.

Here is another example:

[1 REP] (define (sum term low high)
          (define (sum-iter sum index)
            (if (> index high)
                sum
                (sum-iter (+ sum (term index)) (1+ index))))
          (sum-iter 0 low))
SUM
[1 REP] (define (term-proc i)(if (evin? i) 1 0))
TERM-PROC
[1 REP] (pp term-proc)
(DEFINE (TERM-PROC I) (IF (EVIN? I) 1 0))
[1 REP] (sum term-proc 1 5)
Unbound Variable EVIN?
Error!

[2 Error] (debug)
Subproblem Level: 0  Reduction Number: 0
Expression:
EVIN?
within Procedure TERM-PROC
applied to (1)
[3 Debug] b
Subproblem Level: 1  Reduction Number: 0
Expression:
(EVIN? I)
within Procedure TERM-PROC
applied to (1)
[3 Debug] b
Subproblem Level: 2  Reduction Number: 0
Expression:
(IF (EVIN? I) 1 0)
within Procedure TERM-PROC
applied to (1)
[3 Debug] b
Subproblem Level: 3  Reduction Number: 0
Expression:
(+ SUM (TERM INDEX))
within Procedure SUM-ITER
applied to (0 1)
[3 Debug] h
Sub Prb. Procedure Name    Expression
0             TERM-PROC    EVIN?
1             TERM-PROC    (EVIN? I)
2             TERM-PROC    (IF (EVIN? I) 1 0)
3              SUM-ITER    (+ SUM (TERM INDEX))
4              SUM-ITER    (SUM-ITER (+ SUM (TERM INDEX)) (1+ INDEX))

The bug here is that the procedure EVEN? was spelled EVIN?, in the definition of the procedure TERM-PROC. By looking at the history we can see that the procedure SUM was called somewhere at subproblem 4. The command G used below goes to a specified subproblem and reduction. Below we see the call to SUM in subproblem 4, reduction 4.

[3 Debug] g
Subproblem number: 4
Reduction Number (0 through 4 inclusive): 4
Subproblem Level: 4  Reduction Number: 4
Expression:
(SUM TERM-PROC 1 5)
within a MAKE-PACKAGE special form
applied to (#<ENVIRONMENT 13033164>)
[3 Debug] c
Frame created by a MAKE-PACKAGE special form.
Has bindings:
USER-INITIAL-ENVIRONMENT = #<ENVIRONMENT 13833016>
SUM = #<COMPOUND-PROCEDURE SUM>
TERM-PROC = #<COMPOUND-PROCEDURE TERM-PROC>

The environment in which subproblem 4 was being evaluated is the user-initial-environment. The C command displayes the variable bindings in the evaluation environment of the current subproblem. Which in this case is the user-initial-environment. This is where evin? should be defined. The V command evaluates an expression in the current environment.

[3 Debug] v
[3 Eval] (define evin? even?)
EVIN?
[3 Debug] c
Frame created by a MAKE-PACKAGE special form
Has bindings:
USER-INITIAL-ENVIRONMENT = #<ENVIRONMENT 13833016>
SUM = #<COMPOUND-PROCEDURE SUM>
TERM-PROC = #<COMPOUND-PROCEDURE TERM-PROC>
EVIN? = #'<COMPOUND-PROCEDURE EVEN?>
[3 Debug] q
[2 Error] (proceed)

Above we defined the variable evin? to have as its value the procedure even?. We then left the debugger. By typing (proceed) at the error prompt we cause the program to continue with the evaluation of the expression that caused the error, and the procedure completes returning the correct answer.

Scheme language reference

This chapter is a reference manual for the version of Scheme used in 6.003. The explanations here are adapted from [3], which is the standard reference for Scheme implementations. There are some minor differences between this version of Scheme and the one running in the 6.001 lab in 34-401, but these should not cause you trouble.^{1}

Some of the explanations here may provide helpful reminders if you already know Scheme, but we do not recommend that you do more than skim this chapter, and you should definitely not study it as a way to try learn to program in Scheme. To learn to program in Scheme, you should consult [1], which is the text for 6.001.

6.1 Notation and terminology

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

6.1.1 Format of entries

The sections below are organized into entries. Each entry describes one language feature or a group of related features, where a feature is either a syntactic construct or a built-in procedure. An entry begins with one or more header lines of the form

1Besides the different style of interaction with the editor, the difference you are most likely to notice between 6.003 and 6.001 Scheme is that the names of the printing procedures have been changed.

template  category

If category is “syntax”, the entry describes an expression type, and the header line gives the syntax of the expression type. Components of expressions are designated by syntactic variables, which are written using angle brackets, for example, ⟨expression⟩, ⟨variable⟩. Syntactic variables should be understood to denote segments of program text; for example, ⟨expression⟩ stands for any string of characters which is a syntactically valid expression. The notation

⟨thing_{1}⟩ …

indicates zero or more occurrences of a ⟨thing⟩, and

⟨thing_{1}⟩ ⟨thing_{2}⟩ …

indicates one or more occurrences of a ⟨thing⟩.

If category is “procedure”, then the entry describes a procedure, and the header line gives a template for a call to the procedure. Argument names in the template are italicized. Thus the header line

(vector-ref vector k)  procedure

indicates that the procedure vector-ref takes two arguments, a vector vector and an integer k. The header line

(append list …)  procedure

indicates that the append procedure takes zero or more arguments. It is an error for an operation to be presented with an argument that

it is not specified to handle. For succinctness, we follow the convention that if an argument name is also the name of a type, then this implies a restriction on the type of that argument to the procedure. For example, the header line for vector-ref given above dictates that first argument to vector-ref must be a vector. The following naming conventions also imply type restrictions:

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

6.1.2 Evaluation examples

The symbol “⟹” used in program examples should be read “evaluates to.” For example,

    (* 5 8)  ⟹ 40

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

6.1.3 Unspecified values

If the value of an expression is said to be “unspecified,” then the Scheme implementation makes no commitment as to what the value may be. For example

(set! x 3) ⟹ unspecified

Feel free to experiment and determine what Scheme returns in any particular case, but be warned that there is no guarantee that the behavior will not change when there is a system update. On no account should you write programs that rely on a value that has been advertised to be unspecified.

6.1.4 Identifiers

An identifier in Scheme is a sequence of letters, digits, and “extended alphabetic characters” that begins with a character that cannot begin a number is an identifier. In addition, + and - are identifiers. Here are some examples of identifiers:

    lambda                   q
    list->vector             soup
    +                        V17a
    <=?                      a34kTMNs
    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, and #x1AB is the same number as #X1ab.^{2}

Identifiers have several uses within Scheme programs:

2Be aware, however, that Unix distinguishes between upper and lower case letters in file and directory names.

• Certain identifiers are reserved for use as syntactic keywords (see below).

• Any identifier that is not a syntactic keyword may be used as a variable (see section 6.2).

• When an identifier appears as a quoted constant or within a quoted constant, it is being used to denote a symbol (see section 6.7).

The following identifiers are syntactic keywords, and should not be used as variables:

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

6.1.5 Syntax of numbers

A number is expressed as a sequence of digits, followed optionally by a decimal point and more digits, preceded optionally by a + or - sign. Scientific (power of 10) notation is indicated by following the number by the letter e followed optionally by a + or - sign, followed by a sequence of digits. Scheme also supports the conventional notation for complex constants of the form a + bj. Here are some examples of numbers:

    123      +123       -123
    12345668450450945095289203
    3.14159265358979
    123e10
    -123.45e-1
    37.4+1.5j   37.4-1.5j   0+3.5j

Note that complex constants must have a real part and a numerical imaginary part—1.2j and 3.5+j are not legitimate complex constants.

6.1.6 Whitespace and comments

Whitespace characters are spaces and newlines. Whitespace is used for improved readability and as necessary to separate tokens from each other, a token being an indivisible lexical unit such as an identifier or number, but is otherwise insignificant. Whitespace may occur between any two tokens, but not within a token. Whitespace may also occur inside of a string, where it is significant.

A semicolon indicates the start of a comment. The comment continues to the end of the line on which the semicolon appears. Comments are invisible to Scheme, but the end of the line is visible as whitespace. This prevents a comment from appearing in the middle of an identifier or number.

    ;;; 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))))))

6.1.7 Other notations

* / < = > ! ? : $ % _& ~ ^These are extended alphabetic characters, and may be used in identifiers exactly as if they were letters.

. + - These are used in numbers, and may also occur anywhere in an identifier. A delimited plus or minus sign by itself is also an identifier. A delimited period (not occurring within a number or identifier) is used in the notation for pairs (section 6.6), and to indicate a rest-parameter in a formal parameter list (section 6.3.4).

( ) Parentheses are used for grouping and to notate lists (section 6.6).

' The single quote character is used to indicate literal data (section 6.3.2).

` The backquote character is used to indicate almost-constant data (section 6.3.8).

, ,@ The character comma and the sequence comma at-sign are used in conjunction with backquote (section 6.3.8).

" The double quote character is used to delimit strings (section 6.10).

\ Backslash is used in the syntax for character constants and as an escape character within string constants (section 6.10).

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

# Sharp sign is used for a variety of purposes depending on the character that immediately follows it:

#t #f These are the boolean constants (section 6.5).

#\ Introduces a character constant (section 6.9).

#( Introduces a vector constant (section 6.11).

6.2 Variables and bindings

Any identifier that is not a syntactic keyword (see section 6.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 such bindings in effect at some point in a program is known as the environment in effect at that point. The value stored in the location to which a variable is bound is called the variable’s value. By abuse of terminology, the variable is sometimes said to name the value or to be bound to the value. This is not quite accurate, but confusion rarely results from this practice.

Certain expression types are used to create new locations and to bind variables to those locations. 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 6.3.5.

Like Algol and Pascal, and unlike most other dialects of Lisp except for Common Lisp, Scheme is a statically scoped language with 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.

6.3 Expressions

A Scheme expression is a construct that returns a value. Types of expressions include variable references, literals, procedure calls, and constructs specified by syntactic keywords (see section 6.1.4). This section describes all of Scheme’s expression types, except for those dealing with conditionals and logical operations, which are described in section 6.5.

6.3.1 Variable references

⟨variable⟩  syntax

An expression consisting of a variable (section 6.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

6.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

6.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.

6.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 space-delimited period 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)

6.3.5 Binding constructs

The three binding constructs let, let*, and letrec give 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; in a let* expression, the bindings and evaluations are performed sequentially; while in a letrec expression, the bindings are in effect while their initial values are being computed, thus allowing mutually recursive definitions.

(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 ⟨init⟩s are evaluated in the current environment (in some unspecified order), the ⟨variable⟩s 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))

(let* ⟨bindings⟩ ⟨body⟩)  syntax

Syntax: ⟨Bindings⟩ should have the form

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

and ⟨body⟩ should be a sequence of one or more expressions.

Semantics: Let* is similar to let, but the bindings are performed sequentially from left to right, and the region of a binding indicated by (⟨variable⟩ ⟨init⟩) is that part of the let* expression to the right of the binding. Thus the second binding is done in an environment in which the first binding is visible, and so on.

    (let* ((x 1) (y (+ x 1)))
      y)  ⟹ 2

(letrec ⟨bindings⟩ ⟨body⟩)  syntax

Syntax: ⟨Bindings⟩ should have the form

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

and ⟨body⟩ should be a sequence of one or more expressions.

Semantics: The ⟨variable⟩s are bound to fresh locations holding undefined values; the ⟨init⟩s are evaluated in the resulting environment (in some unspecified order); each ⟨variable⟩ is assigned to the result of the corresponding ⟨init⟩; the ⟨body⟩ is evaluated in the resulting environment; and the value of the last expression in ⟨body⟩ is returned. Each binding of a ⟨variable⟩ has the entire letrec expression as its region, making it possible to define mutually recursive procedures.

    (letrec ((even?
              (lambda (n)
                (if (zero? n)
                    #t
                    (odd? (- n 1)))))
             (odd?
              (lambda (n)
                (if (zero? n)
                    #f
                    (even? (- n 1))))))
      (even? 88))
              ⟹ #t

One restriction on letrec is very important: it must be possible to evaluate each ⟨init⟩ without referring to the value of any ⟨variable⟩. If this restriction is violated, then the effect is undefined, and an error may be signalled during evaluation of the ⟨init⟩s. The restriction is necessary because Scheme passes arguments by value rather than by name. In the most common uses of letrec, all the ⟨init⟩s are lambda expressions and the restriction is satisfied automatically.

6.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

6.3.7 Sequencing

(begin ⟨expression_{1}⟩ ⟨expression_{2}⟩ …)  syntax
(sequence ⟨expression_{1}⟩ ⟨expression_{2}⟩ …)  syntax

The ⟨expression⟩s 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.

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

Note: Begin is the sequencing construct in the Scheme standard. Sequence is a synonym provided for compatibility with [1].

6.3.8 Quasiquotation

(quasiquote ⟨template⟩)  syntax
` ⟨template⟩  syntax

“Backquote” or “quasiquote” expressions are useful for constructing a list or vector structure when most but not all of the desired structure is known in advance. If no commas appear within the ⟨template⟩, the result of evaluating ` ⟨template⟩ is equivalent to the result of evaluating '⟨template⟩. If a comma appears within the ⟨template⟩, however, the expression following the comma is evaluated (“unquoted”) and its result is inserted into the structure instead of the comma and the expression. If a comma appears followed immediately by an at-sign (@), then the following expression must evaluate to a list; the opening and closing parentheses of the list are then “stripped away” and the elements of the list are inserted in place of the comma at-sign expression sequence.

    ` (list ,(+ 1 2) 4)  ⟹ (list 3 4)
    (let ((name 'a)) ` (list ,name ',name))
              ⟹ (list a (quote a))
    ` (a ,(+ 1 2) ,@(map abs '(4 -5 6)) b)
              ⟹ (a 3 4 5 6 b)
    ` (( foo ,(- 10 3)) ,@(cdr '(c)) . ,(car '(cons)))
              ⟹ ((foo 7) . cons)
    ` #(10 5 ,(sqrt 4) ,@(map sqrt '(16 9)) 8)
              ⟹ #(10 5 2 4 3 8)

Quasiquote forms may be nested. Substitutions are made only for unquoted components appearing at the same nesting level as the outermost backquote. The nesting level increases by one inside each successive quasiquotation, and decreases by one inside each unquotation.

    ` (a ` (b ,(+ 1 2) ,(foo ,(+ 1 3) d) e) f)
              ⟹ (a ` (b ,(+ 1 2) ,(foo 4 d) e) f)
    (let ((name1 'x)
          (name2 'y))
      ` (a ` (b ,,name1 ,',name2 d) e))
              ⟹ (a ` (b ,x ,'y d) e)

The notations ` ⟨template⟩ and (quasiquote ⟨template⟩) are identical in all respects. ,⟨expression⟩ is identical to (unquote ⟨expression⟩), and ,@⟨expression⟩ is identical to (unquote-splicing ⟨expression⟩).

    (quasiquote (list (unquote (+ 1 2)) 4))
              ⟹ (list 3 4)
    '(quasiquote (list (unquote (+ 1 2)) 4))
              ⟹ ` (list ,(+ 1 2) 4)
         i.e., (quasiquote (list (unquote (+ 1 2)) 4))

Unpredictable behavior can result if any of the symbols quasiquote, unquote, or unquote-splicing appear in positions within a ⟨template⟩ otherwise than as described above.

6.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 space-delimited period 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⟩)).

6.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

6.4.2 Internal definitions

Definitions are also permitted at the beginning of a ⟨body⟩ (that is, the body of a lambda, let, let*, letrec, 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

A ⟨body⟩ containing internal definitions can always be converted into a completely equivalent letrec expression. For example, the let expression in the above example is equivalent to

    (let ((x 5))
      (letrec ((foo (lambda (y) (bar x y)))
               (bar (lambda (a b) (+ (* a b) a))))
        (foo (+ x 3))))

6.5 Booleans and conditionals

The standard boolean objects for true and false are written as #t and #f. 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

(boolean? obj )  procedure

Boolean? returns #t if obj is either #t or #f and returns #f otherwise.

6.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 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.

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

(or ⟨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.

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

6.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 evaluated. If it yields a true value (see section 6.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 ⟨clause⟩s in order until one of them evaluates to a true value (see section 6.5). When a ⟨test⟩ evaluates to a true value, then the remaining ⟨expression⟩s 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 ⟨expression⟩s, then the value of the ⟨test⟩ is returned as the result. If all ⟨test⟩s 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 ⟨expression⟩s 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

6.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 [3] for a careful description of the rationale for these three different predicates.

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

Eqv? is the predicate that you should generally used to test the identity of atomic objects. Eqv? returns #t if obj_{1} and obj_{2} are two symbols that print the same or two numbers that are numerically =. Two procedures are eqv? only if they were created by the same evaluation of the same expression. Two structures (two lists, two vectors, or two character strings) are eqv? if any attempt to modify one of them modifies the other in the same way. In particular, two structures might not be eqv? even if their respective components are eqv?.

    (eqv? 17.945 17.945)  ⟹ #t
    (eqv? 'a 'a)  ⟹ #t
    (eqv? 'a 'b)  ⟹ #f
    (eqv? '(a) '(a))  ⟹ #f
    (eqv? '() '())  ⟹ #t
    (eqv? (cons 1 2) (cons 1 2))⟹ #f
    (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? recursively compares the contents of pairs, vectors, and strings, applying eqv? on atomic objects like numbers and symbols. A rule of thumb is that objects are generally equal? if they print the same. Equal? may fail to terminate if its arguments are circular data structures.

    (equal? 'a 'a)  ⟹ #t
    (equal? '(a) '(a))  ⟹ #t
    (equal? '(a (b) c) '(a (b) c))
                                ⟹ #t
    (equal? "abc" "abc")  ⟹ #t
    (equal? 2 2)  ⟹ #t
    (equal? (make-vector 5 'a)
            (make-vector 5 'a)) ⟹ #t

    (equal? (lambda (x) x)
            (lambda (y) y))  ⟹ unspecified

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

Eq? is similar to eqv? except that in some cases it is capable of discerning distinctions finer than those detectable by eqv?. From an implementation point of view, two objects are eq? if they share the same location in memory. In particular, whether or not two numbers are eq? is highly implementationdependent.

    (eq? 'a 'a)  ⟹ #t
    (eq? '(a) '(a))  ⟹ #f
    (eq? "a" "a")  ⟹ unspecified

(eq? "" "") ⟹ unspecified

    (eq? '() '())  ⟹ #t

(eq? 2 2) ⟹ unspecified

    (eq? #\A #\A)  ⟹ unspecified

6.6 Pairs and lists

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

and set-cdr!.

Pairs are used primarily to represent lists. A list can be defined recursively as either the empty list or a pair whose cdr is a list. The objects in the car fields of successive pairs of a list are the elements of the list. For example, a two-element list is a pair whose car is the first element and whose cdr is a pair whose car is the second element and whose cdr is the empty 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 (external representation) 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)

(pair? obj )  procedure

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

    (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)

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

Constructs a pair whose car is obj_{1} and whose cdr is (cons* obj_{2} …). When there are only two arguments, cons* behaves like cons. With a single argument, cons* returns its argument (by convention).

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

(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.

(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)  ⟹ ()

(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

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)))))

(list-ref list k)  procedure

Returns the kth element of list. (This is the same as the car of (list-tail list k).)

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

(last-pair list)  procedure

Returns the last pair in the nonempty, possibly improper, list list. Could be defined by

    (define last-pair
      (lambda (x)
        (if (pair? (cdr x))
            (last-pair (cdr x))
            x)))

(memq obj list)  procedure
(memv obj list)  procedure
(member 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)

(assq obj alist)  procedure
(assv obj alist)  procedure
(assoc 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?.

    (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.

6.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 6.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 one-character symbols or numbers. Implode returns a symbol whose name is the concatenation of the elements in the list.

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

(generate-uninterned-symbol)  procedure
(generate-uninterned-symbol symbol)  procedure

Returns a symbol that is guaranteed to be different (not eqv?) from any other symbol. If an argument ⟨symbol⟩ is specified, then 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  ⟹  FACT342
    (eqv? s s)  ⟹ #t
    (eqv? s 'FACT342)  ⟹ #f

6.8 Numbers

Refer to section 6.1.1 for a summary of the naming conventions used to specify restrictions on the types of arguments to numerical routines.

(number? obj )  procedure
(complex? obj )  procedure
(real? 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

(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
(modulo 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}
    (modulo n_{1} n_{2})  ⟹ n_{4}

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 and modulo differ on negative arguments—the remainder always has the sign of the dividend, the modulo always has the sign of the divisor:

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

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

(numerator q)  procedure
(denominator q)  procedure

These procedures return the numerator or denominator of their argument.

    (numerator (/ 6 4))  ⟹ 3
    (denominator (/ 6 4))  ⟹ 2

(gcd n_{1} …)  procedure
(lcm 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
    (lcm 32 -36)  ⟹ 288
    (lcm)  ⟹ 1

(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
(asin z)  procedure
(acos z)  procedure
(atan z)  procedure
(atan y x)  procedure

Log computes the natural logarithm of z (not the base 10 logarithm). Asin, acos, and atan compute arcsine (sin^{−1}), arccosine (cos^{−1}), and arctangent (tan^{−1}), respectively. The two-argument variant of atan computes

(angle (make-rectangular x y)) (see below).

In general, the mathematical functions log, arcsine, arccosine, and arctangent are multiply defined. For nonzero real 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. The value of log z when z is complex is defined according to the formula

log z = log magnitude(z) + i angle(z)

With log defined this way, the values of sin^{−1} z, cos^{−1} z, and tan^{−1} z are according to the following formulae:

sin^{−1} z = −i log(iz + \sqrt{1 − z^{2}})
cos^{−1} z = −i log(z + i\sqrt{1 − z^{2}})
tan^{−1} z = −i log((1 + iz)\sqrt{1/(1 + z^{2})})

The above specification follows [5], which in turn follows [2]; refer to these sources for more detailed discussion of branch cuts, boundary conditions, and implementation of these functions.

(sqrt z)  procedure

Returns the principal square root of z. The result will have either positive real part, or zero real part and non-negative imaginary part.

(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.

(make-rectangular x_{1} x_{2})  procedure

(make-polar x_{3} x_{4})  procedure

(real-part z)  procedure
(imag-part z)  procedure
(magnitude z)  procedure

(angle z)  procedure

(conjugate z)  procedure

Suppose x_{1}, x_{2}, x_{3}, and x_{4} are real numbers and z is a complex number such that

z = x_{1} + x_{2}i = x_{3} · eix^{4}

Then make-rectangular and make-polar return z, real-part returns x_{1},

imag-part returns x_{2}, magnitude returns x_{3}, angle returns x_{4}, and conjugate returns the complex conjugate of z. In the case of angle, whose value is not uniquely determined by the preceding rule, the value returned will be the one in the range −π (exclusive) to π (inclusive).

Note: Magnitude is the same as abs.

(random k)  procedure

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

6.9 Characters

Characters are atomic objects that represent printed characters such as letters and digits. Characters are written using the notation #\⟨character⟩ or #\⟨character name⟩. For example:

#\a  ; lower case letter
#\A  ; upper case letter
#\(  ; left parenthesis
#\space  ; the space character
#\newline ; the newline character

Characters written in the #\ notation are self-evaluating. That is, they do not have to be quoted in programs.

(char? obj )  procedure

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

(char=? char_{1} char_{2})  procedure

Returns #t if char_{1} and char_{2} are the same character. Case is significant, that is, (char=? #\A #\a) returns #f. Both char_{1} and char_{2} must be characters.

6.10 Strings

Strings are sequences of characters. Strings are written as sequences of characters enclosed within doublequotes ("). A doublequote can be written inside a string only by escaping it with a backslash (\), as in

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

A backslash can be written inside a string only by escaping it with another backslash. Scheme does not specify the effect of a backslash within a string that is not followed by a doublequote or backslash.

(string? obj )  procedure

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

6.11 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 procedure make-vector. 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.

(make-vector size)  procedure

(make-vector size fill)  procedure

Returns a newly allocated vector of size elements. If a second argument is given, then each element is initialized to fill. Otherwise the initial contents of each element is unspecified.

(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-length 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")

(vector->list vector)  procedure

(list->vector list)  procedure

Vector->list returns a newly created list of the objects contained in the elements of vector. List->vector returns a newly created vector initialized to the elements of the list list.

    (vector->list '#(dah dah didah))
              ⟹ (dah dah didah)
    (list->vector '(dididit dah))
              ⟹ #(dididit dah)

(vector-fill! vector fill)  procedure

Stores fill in every element of vector. The value returned by vector-fill! is unspecified.

6.12 Control features

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

(apply proc args)  procedure
(apply proc arg_{1} … args)  procedure

Proc must be a procedure and args must be a list. The first form calls proc with the elements of args as the actual arguments. The second form is a generalization of the first that calls proc with the elements of (append (list arg_{1} …) args) as the actual arguments.

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

(map proc list)  procedure
(map proc list_{1} list_{2} …)  procedure

Proc must be a procedure of one argument and the lists must be lists. If more than one list is given, then they must all be the same length. Map applies proc element-wise to the elements of the lists and returns a list of the results. The order in which proc is applied to the elements of the lists is unspecified.

    (map cadr '((a b) (d e) (g h)))
              ⟹ (b e h)
    (map (lambda (n) (expt n n))
         '(1 2 3 4 5))
              ⟹ (1 4 27 256 3125)
    (map + '(1 2 3) '(4 5 6)) ⟹ (5 7 9)
    (let ((count 0))
      (map (lambda (ignored)
             (set! count (+ count 1))
             count)

'(a b c))) ⟹ unspecified

(for-each proc list)  procedure
(for-each proc list_{1} list_{2} …)  procedure

The arguments to for-each are like the arguments to map, but for-each calls proc for its side effects rather than for its values. Unlike map, for-each is guaranteed to call proc on the elements of the lists in order from the first element to the last, and the value returned by for-each is unspecified.

    (let ((v (make-vector 5)))
      (for-each (lambda (i)
                  (vector-set! v i (* i i)))
                '(0 1 2 3 4))
      v)  ⟹ #(0 1 4 9 16)

6.13 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)

    (define a-stream
      (letrec ((next
                (lambda (n)
                  (cons n (delay (next (+ n 1)))))))
        (next 0)))
    (define head car)
    (define tail
      (lambda (stream) (force (cdr stream))))
    (head (tail (tail a-stream)))
                                ⟹ 2

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 (begin (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

6.14 Input and output

6.14.1 Ports

Ports represent input and output devices. To Scheme, an input device is a Scheme object that can deliver characters upon command, while an output device is a Scheme object that can accept characters.

console-input-port  variable
console-output-port  variable

These variables are initially bound to the ports for input and output to the console.

(open-input-file filename)  procedure

Takes a string naming an existing file and returns an input port capable of delivering characters from the file. If the file cannot be opened, an error is signalled.

(open-output-file filename)  procedure

Takes a string naming an output file to be created and returns an output port capable of writing characters to a new file by that name. If the file cannot be opened, an error is signalled.

(close-input-port port)  procedure
(close-output-port port)  procedure

Closes the file associated with port, rendering the port incapable of delivering or accepting characters. These routines have no effect if the file has already been closed. The value returned is unspecified.

(call-with-input-file string proc)  procedure
(call-with-output-file string proc)  procedure

Proc should be a procedure of one argument, and string should be a string naming a file. For call-with-input-file, the file must already exist; for call-with-output-file, the effect is unspecified if the file already exists. These procedures call proc with one argument: the port obtained by opening the named file for input or output. If the file cannot be opened, an error is signalled. If the procedure returns, then the port is closed automatically and the value yielded by the procedure is returned.

(input-port? obj )  procedure
(output-port? obj )  procedure

Returns #t if obj is an input port or output port respectively, otherwise returns #f.

(current-input-port)  procedure
(current-output-port)  procedure

Returns the current default input or output port.

(with-input-from-file string thunk)  procedure
(with-output-to-file string thunk)  procedure

Thunk must be a procedure of no arguments, and string must be a string naming a file. For with-input-from-file, the file must already exist; for with-output-to-file, the effect is unspecified if the file already exists. The file is opened for input or output, an input or output port connected to it is made the default value returned by current-input-port or current-output-port, and the thunk is called with no arguments. When the thunk returns, the port is closed and the previous default is restored.

With-input-from-file and with-output-to-file return the value yielded

by thunk. Furthermore, when these procedures return, they close the default port and restore the previous default.

6.14.2 Input

(read)  procedure
(read port)  procedure

Read returns the next object parsable from the given input port, updating port 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 an end of file object is returned. The port remains open, and further attempts to read will also return an end of file object. If an end of file is encountered after the beginning of an object’s written representation, but the written representation is incomplete and therefore not parsable, an error is signalled.

The port argument may be omitted, in which case it defaults to the value returned by current-input-port. It is an error to read from a closed port.

(read-char)  procedure

(read-char port)  procedure

Returns the next character available from the input port, updating the port to point to the following character. If no more characters are available, an end of file object is returned. Port may be omitted, in which case it defaults to the value returned by current-input-port.

(load filename)  procedure

Filename should be a string naming an existing file containing Scheme code. The load procedure reads expressions and definitions from the file and evaluates them sequentially. The load procedure does not affect the values re-

turned by current-input-port and current-output-port. Load returns

an unspecified value.

(char-ready?)  procedure
(char-ready? port)  procedure

Returns #t if a character is ready on the input port and returns #f otherwise. If char-ready returns #t then the next read-char operation on the given port is guaranteed not to hang. If the port is at end of file then char-ready? returns #t. Port may be omitted, in which case it defaults to the value returned by current-input-port. Char-ready? exists to make it possible for a program to accept characters from interactive ports without getting stuck waiting for input.

(eof-object? obj )  procedure

Returns #t if obj is an end of file object, otherwise returns #f.

6.14.3 Output

(write obj )  procedure
(write obj port)  procedure

Writes a representation of obj to the given port. Strings that appear in the written representation are enclosed in doublequotes, and within those strings backslash and doublequote characters are escaped by backslashes. Write returns an unspecified value. The port argument may be omitted, in which case it defaults to the value returned by current-output-port.

(display obj )  procedure
(display obj port)  procedure

Writes a representation of obj to the given port. Strings that appear in the written representation are not enclosed in doublequotes, and no characters are escaped within those strings. In those implementations that have a distinct character type, character objects in the representation appear as if written by write-char. Display returns an unspecified value. The port argument may be omitted, in which case it defaults to the value returned

by current-output-port.

Rationale: Write is intended for producing machine-readable output and display is for producing human-readable output.

(pp obj )  procedure

“Pretty prints” obj to the current output port. That is, pp displays obj formatted so as to clearly show its structure. For example, if obj is a long list, then the displayed representation will be broken over a number of lines and indented. If obj is a procedure then the text of obj will displayed.

(newline)  procedure

(newline port)  procedure

Writes an end of line to port. Exactly how this is done differs from one operating system to another. Returns an unspecified value. The port argument may be omitted, in which case it defaults to the value returned

by current-output-port.

(write-char char)  procedure
(write-char char port)  procedure

Writes the character char (not a written representation of the character) to the given port and returns an unspecified value. The port argument may be omitted, in which case it defaults to the value returned by

current-output-port.

(transcript-on filename)  procedure

(transcript-off)  procedure

Filename must be a string naming an output file to be created. The effect of transcript-on is to open the named file for output, and to cause a transcript of subsequent interaction between the user and the Scheme system to be written to the file. The transcript is ended by a call to transcript-off, which closes the transcript file. Only one transcript may be in progress at any time. The values returned by these procedures are unspecified.

6.15 Environments and evaluation

An environment is the set of bindings for variables that is in effect at some point in a program. (See section 6.2.) Environments in Scheme are firstclass 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.

6.16 Errors, breakpoints, and debugging

When Scheme encounters an error, it enters an error read-eval-print loop which accepts expressions to be evaluated in the environment of the error. One error level can be nested inside another and the user can move between error levels, or return to the top level. Breakpoints, which are similar to error breaks, can also be triggered by executing bkpt expressions. There are also special subsystems called debug and where to aid in debugging. This section lists Scheme’s debugging commands, but refer to chapter 5 for a more extended description of errors and breakpoints.

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

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

(bkpt message object)  syntax

Sets a breakpoint . Displays message and object and enters a breakpoint read-eval-print loop in the current environment. To proceed from a breakpoint, use the proceed procedure. See section 5.2.

(proceed)  procedure

Continues evaluation that was interrupted by a breakpoint. See section 5.2.

(debug)  procedure

Enters the history examination system, which allows the user to examine the history of the execution of an expression by issuing one-letter commands. See section 5.5.

(where)  procedure
(where procedure)  procedure

Enters the environment examination system, which allows the user to examine and modify variables and bindings by issuing one-letter commands. With no argument, the environment examined is the one in which where was evaluated. If procedure is supplied as an argument, then the environment examined is the one in which procedure was defined. See section 5.4.

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

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

Trace-both performs both trace-entry and trace-exit. Trace is the

same as trace-entry. See section 6.16 for examples of tracing procedures.

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

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

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

See section 6.16 for examples of setting breakpoints on procedures.

(*proc*)  procedure

(*result*)  procedure

(*args*)  procedure

These three procedures are used only at a breakpoint. *Proc* returns the “broken” procedure, *args* returns a list of the arguments supplied to the “broken” procedure, and *result* returns the result about to be returned by the ”broken” procedure. *Result* is used only at exit breaks. See section 6.16 for examples of how these are used.

(untrace )  procedure

(untrace procedure)  procedure

Removes any breakpoints and trace messages set for procedure. With no argument, removes traces and breakpoints for all procedures.

6.17 Miscellaneous

(procedure? obj )  procedure

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

    (procedure? car)  ⟹ #t
    (procedure? 'car)  ⟹ #f
    (procedure? (lambda (x) (* x x)))
                                ⟹ #t
    (procedure? '(lambda (x) (* x x)))
                                ⟹ #f

(runtime)  procedure

Returns the amount of time (in milliseconds) that the system has been running.

(object-type obj )  procedure

Returns the primitive datatype of the object obj . The following are the datatypes that would be encountered in user code: character, string,

interned-symbol, uninterned-symbol, environment, pair, vector, number,
procedure, primitive-procedure, true, null, delayed.

(enable-language-features)  procedure

The Scheme system includes many more built-in procedures than are documented in this manual. Most of these are of value 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.

6.18 Graphics

This section describes the basic graphics primitives available on the Bobcat computers for use in 6.003.

(position-pen x y)  procedure

Sets the graphics pen at the point whose coordinates are (x, y). On the Bobcat screen, both x and y range between ±512.

(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).

(draw-point x y)  procedure
(clear-point x y)  procedure

Plots (respectively, clears) the point at (x, y).

(clear-graphics)  procedure

Clears the screen.

Bibliography

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

[2] Paul Penfield, Jr. Principal values and branch cuts in complex APL. In APL ’81 Conference Proceedings, pages 248–256. ACM SIGAPL, San Francisco, September 1981. Proceedings published as APL Quote Quad 12(1), ACM, September 1981.

[3] Jonathan Rees and William Clinger, editors. Revised^{3} report on the algorithmic language Scheme. Newsletter of the ACM Special Interest Group on Programming Lnaguages, November 1986.

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

[5] Guy Lewis Steele, Jr. Common Lisp: The Language. Digital Press, Burlington MA, 1984.

Index

The principal entry for each term, procedure, or keyword is listed first, separated from the others by a semicolon.

(proceed) 43

* 86

*args* 103; 45
*default-edit* buffer 15
*proc* 103; 45
*result* 103; 45
*scheme* 13

+ 86; 61

- 86; 61

-j 28

/ 86

2pi 28

< 86

<= 86

= 86

=> 76

> 86

>= 86

abs 87; 90

acos 89
add-poly 22
alphaless? 84
and 75
angle 90
append 82

                                  apply 93
                                  asin 89
                                  assoc 83; 84

assq 83; 84 assv 83; 84 at-sign 71

                                  atan 89

backing up disks 11

backquote 71

                                  begin 70

binding 64

binding construct 64

bkpt 102; 42

                                  bode-plot 27
                                  boolean? 74

bound 64 break 102; 42

                                  break-both 102; 42
                                  break-entry 102; 42
                                  break-exit 102; 42, 45

buffer 7, 15

                                  caar 81
                                  caddr 81
                                  cadr 81

call 66

call by need 95

                                  call-with-input-file 97
                                  call-with-output-file 97

car 80; 78, 81

cdddar 81
cddddr 81

cdr 80; 78, 81

ceiling 88
char-ready 99
char-ready? 99
char=? 91
char? 91
character 103
clear-graphics 104
clear-point 104
close-input-port 97
close-output-port 97

combination 66 comma 71 comment 63 complex numbers 19

complex? 85
cond 76
conjugate 90

cons 80; 78

cons* 80
cons-stream 95; 94
console-input-port 96
console-output-port 96

control character 3

cos 89
ctl-x z 15
current-input-port 97; 98, 99
current-output-port 97; 98, 99,

100 cursor 3

debug 102; 40, 52

define 72; 101
delay 95; 96
delayed 103
denominator 88
display 99

                                  display-poly 22
                                  div-poly 23

dotted pair 78

                                  draw-line-to 104
                                  draw-point 104

echo area 9

                                  else 76

empty list 78; 74, 79, 80, 81

empty stream 95

                                  empty-stream? 95
                                  enable-language-features 104

environment 100

                                  environment 103
                                  environment? 101
                                  eof-object? 99

eq? 78; 83

                                  equal? 77; 83

eqv? 77; 78, 80, 83, 84, 85

error 101; 42

error read-eval-print loop 101 error rep loop 14

                                  esc-o 15

escape character 3

                                  eval 100

evaluating scheme expressions 13,

35

                                  even? 86
                                  exp 88
                                  explode 84
                                  expt 89

extended commands 9

false 73

                                  #false 73
                                  false 74
                                  floor 88
                                  for-each 94
                                  force 95; 96

free software foundation 29

gcd 88
generate-uninterned-symbol 85

graphics 104

graphics buffer 15

hardcopy 12 head 95; 94

identifier 61; 64

if 75
imag-part 90
implode 85

improper list 79

initialize-floppy 12

initializing disks 12

input-port? 97
integer? 85

internal definition 73

interned-symbol 103

j 28

keyword 62, 64

lambda 66

lambda expression 64

last-pair 83

lazy evaluation 95

lcm 88
length 81

let 67, 68 let* 69; 67

letrec 69; 67

list 78 list 81; 92

list->vector 93
list-graphs 27
list-ref 82

list-tail 82

load 98; 18

load problem set 18

log 88; 89

logout 10
magnitude 90
make-environment 101
make-polar 90
make-rectangular 90; 19
make-vector 92

map 93; 94

max 86
member 83; 84

memq 83; 84 memv 83; 84 meta character 3

min 86

mode line 8

modulo 87
mul-poly 22

named let 68

negative? 86
newline 100
not 74
null 103
null? 81

number 62, 85

number 103
number? 85
numerator 88
object-type 103
odd? 86
open-input-file 97
open-output-file 97
operator->procedure 21
operator->rat-func 24
operator-value 20

operator? 20

operators 20

or 75
output-port? 97

pair 78

pair 103
pair? 79

path name 10

pfe->rat-func 26
pfe->time 26
pi 28
plot-f-resp 27
poly->proc 24
poly->roots 23
position-pen 104
positive? 85
pp 99

pretty print 99

primitive-procedure 103
print-buffer 12
print-file 12
print-screen 12

printer 12

procedure 103

procedure call 66

procedure->operator 21
procedure? 103
proceed 102

promise 95

quasiquote 71
quote 65
quotient 87
random 90
rat-func->pfe 25
read 98
read-char 98; 99

read-eval-print 14, 41

                                  real-part 90
                                  real? 85

reduction 48

region 64; 67, 68, 69, 70

                                  regraph 27
                                  remainder 87
                                  remove-graph 28

residues 26

                                  reverse 82
                                  roots->poly 23
                                  round 88
                                  runtime 103

s 21

                                  save-floppy 11
                                  scale-poly 23
                                  sequence 70
                                  set! 70
                                  set-car! 81; 78
                                  set-cdr! 81; 78, 79
                                  set-fields! 27

sexp (symbolic expression) 34

                                  sin 89
                                  sqrt 89

stream 94

                                  string 103
                                  string? 91
                                  sub-poly 22

subproblem 48

                                  symbol? 84

syntactic keyword 62, 64

tail 95; 94

                                  tan 89
                                  the-empty-stream 95
                                  the-environment 101

top level environment 64

                                  trace 102
                                  trace-both 102

trace-entry 102
trace-exit 102
transcript-off 100; 18
transcript-on 100; 18

transcripts 18 true 73, 75, 76

#true 73

true 74; 103

truncate 88

unbound 64; 65, 73

uninterned-symbol 103
untrace 103
user-initial-environment 101

variable 64; 62, 65

vector 92; 103
vector->list 93
vector-fill! 93
vector-length 92
vector-ref 92
vector-set! 92
vector? 92

where 102; 40 whitespace 63 window 15

window-all 17
window-edit 17
window-scheme 17
window-scheme-edit 17
window-scheme-graphics 17

windows 8

with-input-from-file 97; 98
with-output-to-file 97; 98
write 99
write-char 100; 99
zero? 85