Go to the first, previous, next, last section, table of contents.


Using Scheme

This chapter describes how to use Scheme to evaluate expressions and load programs. It also describes how to save custom "world images", and how to control the garbage collector. Subsequent chapters will describe how to use the compiler, and how to debug your programs.

The Read-Eval-Print Loop

When you first start up Scheme from the command line (i.e. not under Edwin), you will be typing at a program called the Read-Eval-Print Loop (abbreviated REPL). It displays a prompt at the left hand side of the screen whenever it is waiting for input. You then type an expression (terminating it with RET). Scheme evaluates the expression, prints the result, and gives you another prompt.

The Prompt and Level Number

The REPL prompt normally has the form

1 ]=>

The `1' in the prompt is a level number, which is always a positive integer. This number is incremented under certain circumstances, the most common being an error. For example, here is what you will see if you type f o o RET after starting Scheme:

;Unbound variable: foo
;To continue, call RESTART with an option number:
; (RESTART 3) => Specify a value to use instead of foo.
; (RESTART 2) => Define foo to a given value.
; (RESTART 1) => Return to read-eval-print level 1.

2 error> 

In this case, the level number has been incremented to `2', which indicates that a new REPL has been started (also the prompt string has been changed to remind you that the REPL was started because of an error). The `2' means that this new REPL is "over" the old one. The original REPL still exists, and is waiting for you to return to it, for example, by entering (restart 1). Furthermore, if an error occurs while you are in this REPL, yet another REPL will be started, and the level number will be increased to `3'. This can continue ad infinitum, but normally it is rare to use more than a few levels.

The normal way to get out of an error REPL and back to the top level REPL is to use the C-g interrupt. This is a single-keystroke command executed by holding down the CTRL key and pressing the G key. C-g always terminates whatever is running and returns you to the top level REPL immediately.

Note: The appearance of the `error>' prompt does not mean that Scheme is in some weird inconsistent state that you should avoid. It is merely a reminder that your program was in error: an illegal operation was attempted, but it was detected and avoided. Often the best way to find out what is in error is to do some poking around in the error REPL. If you abort out of it, the context of the error will be destroyed, and you may not be able to find out what happened.

Interrupting

Scheme has several interrupt keys, which vary depending on the underlying operating system: under Unix, C-g and C-c; under Windows, C-b, C-x, C-u, C-g and C-c; under OS/2, C-b, C-x, C-u and C-g. The C-g key stops any Scheme evaluation that is running and returns you to the top level REPL. C-c prompts you for another character and performs some action based on that character. It is not necessary to type RET after C-g or C-c, nor is it needed after the character that C-c will ask you for.

Here are the definitions of the more common interrupt keys; on systems that support C-c, type C-c ? for more possibilities. Note that in any given implementation, only a subset of the following keys is available.

C-c C-c
C-g
Abort whatever Scheme evaluation is currently running and return to the top-level REPL. If no evaluation is running, this is equivalent to evaluating
(cmdl-interrupt/abort-top-level)
C-c C-x
C-x
Abort whatever Scheme evaluation is currently running and return to the "current" REPL. If no evaluation is running, this is equivalent to evaluating
(cmdl-interrupt/abort-nearest)
C-c C-u
C-u
Abort whatever Scheme evaluation is running and go up one level. If you are already at level number 1, the evaluation is aborted, leaving you at level 1. If no evaluation is running, this is equivalent to evaluating
(cmdl-interrupt/abort-previous)
C-c C-b
C-b
Suspend whatever Scheme evaluation is running and start a breakpoint REPL. The evaluation can be resumed by evaluating
(continue)
in that REPL at any time.
C-c q
Similar to typing (exit) at the REPL, except that it works even if Scheme is running an evaluation, and does not request confirmation.
C-c z
Similar to typing (quit) at the REPL, except that it works even if Scheme is running an evaluation.
C-c i
Ignore the interrupt. Type this if you made a mistake and didn't really mean to type C-c.
C-c ?
Print help information. This will describe any other options not documented here.

Restarting

Another way to exit a REPL is to use the restart procedure:

procedure+: restart [k]
This procedure selects and invokes a restart method. The list of restart methods is different for each REPL; in the case of an error REPL, this list is printed when the REPL is started:

;Unbound variable: foo
;To continue, call RESTART with an option number:
; (RESTART 3) => Specify a value to use instead of foo.
; (RESTART 2) => Define foo to a given value.
; (RESTART 1) => Return to read-eval-print level 1.

2 error> 

If the k argument is given, it must be a positive integer index into the list (in the example it must be between one and three inclusive). The integer k selects an item from the list and invokes it. If k is not given, restart prints the list and prompts for the integer index:

2 error> (restart)
;Choose an option by number:
;  3: Specify a value to use instead of foo.
;  2: Define foo to a given value.
;  1: Return to read-eval-print level 1.

Option number:

The simplest restart methods just perform their actions. For example:

2 error> (restart 1)
;Abort!

1 ]=>

Other methods will prompt for more input before continuing:

2 error> (restart)
;Choose an option by number:
;  3: Specify a value to use instead of foo.
;  2: Define foo to a given value.
;  1: Return to read-eval-print level 1.

Option number: 3

Value to use instead of foo: '(a b)
;Value: (a b)

1 ]=>

The Current REPL Environment

Every REPL has a current environment, which is the place where expressions are evaluated and definitions are stored. When Scheme is started, this environment is the value of the variable user-initial-environment. There are a number of other environments in the system, for example system-global-environment, where the runtime system's bindings are stored.

You can get the current REPL environment by evaluating

(nearest-repl/environment)

There are several other ways to obtain environments. For example, if you have a procedure object, you can get a pointer to the environment in which it was closed by evaluating

(procedure-environment procedure)

Your programs create new environments whenever a procedure is called.

Here is the procedure that changes the REPL's environment:

procedure+: ge environment
Changes the current REPL environment to be environment (ge stands for "Goto Environment"). Environment is allowed to be a procedure as well as an environment object. If it is a procedure, then the closing environment of that procedure is used in its place.

procedure+: pe
This procedure is useful for finding out which environment you are in (pe stands for "Print Environment"). If the current REPL environment belongs to a package, then pe returns the package name (a list of symbols). If the current REPL environment does not belong to a package then the environment is returned.

procedure+: gst syntax-table
In addition to the current environment, each REPL maintains a current syntax table. The current syntax table tells the REPL which keywords are used to identify special forms (e.g. if, lambda). If you write macros, you may want to make your own syntax table, in which case it is useful to be able to make that syntax table be the current one; gst allows you to do that.

Loading Files

To load files of Scheme code, use the procedure load:

procedure: load filename [environment [syntax-table [purify?]]]
Filename may be a string naming a file, or a list of strings naming multiple files. Environment, if given, is the environment to evaluate the file in; if not given the current REPL environment is used. Likewise syntax-table is the syntax table to use.

The optional argument purify? is a boolean that says whether to move the contents of the file into constant space after it is loaded but before it is evaluated. This is performed by calling the procedure purify (see section Garbage Collection). If purify? is given and true, this is done; otherwise it is not.

load determines whether the file to be loaded is binary or source code, and performs the appropriate action. By convention, files of source code have a pathname type of "scm", and files of binary SCode have pathname type "bin". Native-code binaries have pathname type "com". (See the description of pathname-type in the reference manual.)

variable+: load-noisily?
If load-noisily? is set to #t, load will print the value of each expression in the file as it is evaluated. Otherwise, nothing is printed except for the value of the last expression in the file. (Note: the noisy loading feature is implemented for source-code files only.)

variable+: load/default-types
When load is given a pathname without a type, it uses the value of this variable to determine what pathname types to look for and how to load the file. load/default-types is a list of associations that maps pathname types (strings) to loader procedures. load tries the pathname types in the order that they appear in the list. The initial value of this variable has pathname types in this order:

"com" "so" "sl" "bin" "scm"

This means that, for example, (load "foo") will try to load `foo.com' first, and `foo.scm' only after looking for and failing to find the other pathname types.

All pathnames are interpreted relative to a working directory, which is initialized when Scheme is started. The working directory can be obtained by calling the procedure pwd or modified by calling the procedure cd; see the reference manual for details. Files may be loaded when Scheme first starts; see the `-load' command-line option for details.

procedure+: load-option symbol [no-error?]
Loads the option specified by symbol; if already loaded, does nothing. Returns symbol; if there is no such option, an error is signalled. However, if no-error? is specified and true, no error is signalled in this case, and #f is returned.

A number of built-in options are defined:

compress
Code to compress and uncompress files. Undocumented. Used by the runtime system for compression of compiled-code debugging information.
format
The format procedure. Documented in the Reference Manual.
hash-table
The hash-table data type. Documented in the Reference Manual.
ordered-vector
Code to search and do completion on vectors of ordered elements. Undocumented.
rb-tree
The red-black tree data type. Documented in the Reference Manual.
stepper
Code to step through the evaluation of Scheme expressions. Undocumented. Used by the Edwin command M-x step-expression.
subprocess
Code to run other programs as subprocesses of the Scheme process; implemented under Unix and OS/2 only. Undocumented, but used extensively by Edwin.
wt-tree
The weight-balanced tree data type. Documented in the Reference Manual.

In addition to the built-in options, you may define other options to be loaded by load-options by modifying the file `optiondb.scm' on the library path. An example file is included with the distribution; normally this file consists of a series of calls to the procedure define-load-option, terminated by the expression

(further-load-options standard-load-options)

procedure+: define-load-option symbol thunk ...
Each thunk must be a procedure of no arguments. Defines the load option named symbol. When the procedure load-option is called with symbol as an argument, the thunk arguments are executed in order from left to right.

World Images

A world image, also called a band, is a file that contains a complete Scheme system, perhaps additionally including user application code. Scheme provides a method for saving and restoring world images. The method writes a file containing all of the Scheme code in the running process. The file `runtime.com' that is loaded by the microcode is just such a band. To make your own band, use the procedure disk-save.

procedure+: disk-save filename [identify]
Causes a band to be written to the file specified by filename. The optional argument identify controls what happens when that band is restored, as follows:

not specified
Start up in the top-level REPL, identifying the world in the normal way.
a string
Do the same thing except print that string instead of `Scheme' when restarting.
the constant #t
Restart exactly where you were when the call to disk-save was performed. This is especially useful for saving your state when an error has occurred and you are not in the top-level REPL.
the constant #f
Just like #t, except that the runtime system will not perform normal restart initializations; in particular, it will not load your init file.

To restore a saved band, give the `-band' option when starting Scheme. Alternatively, evaluate (disk-restore filename), which will destroy the current world, replacing it with the saved world. The argument to disk-restore may be omitted, in which case it defaults to the filename from which the current world was last restored.

Note: with the C back end, disk-save is not very useful. The reason is that compiled procedures are compiled C code that has been dynamically linked in, and disk-save does not save any C procedures. Your system is a C back end system if the following expression does not evaluate to #f:

(system-library-directory-pathname "shared")

Note: when restoring a saved band, the Scheme executable must be configured with a large enough constant space and heap to hold the band's contents. If you attempt to restore a band using the `-band' option, and the band is too large, Scheme will write an error message that tells you the appropriate command-line options needed to load that band. If you attempt restore a too-large band using disk-restore, Scheme will signal an error, but will not provide the configuration information. In general, the configuration that was used to save a band is sufficiently large to restore it.

Garbage Collection

This section describes procedures that control garbage collection. See section Memory Usage, for a discussion of how MIT Scheme uses memory.

procedure+: gc-flip [safety-margin]
Forces a garbage collection to occur. Returns the number of words of storage available after collection, an exact non-negative integer.

Safety-margin determines the number of words of storage available for system tasks in-between detecting the need for a garbage collection and entering the garbage collector proper. (An example of such a system task is changing the run-light to show "gc" when scheme is running under Emacs.) Note well: you should not specify safety-margin unless you know what you are doing. If you specify a value that is too small, you can put Scheme in an unusable state.

procedure+: purify object [pure-space? [queue?]]
Moves object from the heap into constant space. Has no effect if object is already stored in constant space. Object is moved in its entirety; if it is a compound object such as a list, a vector, or a record, then all of the objects that object points to are also moved to constant space.

There are three important effects associated with moving an object to constant space. The first and most important effect is that the object takes up half as much space, because when in the heap, the system must reserve space for the object in both the active heap and the inactive heap; if the object is in constant space it is not copied and therefore no extra space is required. The second effect is that garbage collection will take less time, because object will no longer be copied. The third effect is that the space allocated to object is permanently allocated, because constant space is never cleaned; any unreachable objects in constant space remain there until the Scheme process is terminated.

The optional argument pure-space? is obsolete; it defaults to #t and when explicitly specified should always be #t.

The optional argument queue? specifies whether object should be moved to constant space immediately, or should be queued to be moved during the next garbage collection. This argument defaults to #t. The reason for queuing these requests is that moving an object to constant space requires a garbage collection to occur, a relatively slow process. By queuing the requests, this overhead is avoided, because moving an object during a garbage collection has no effect on the time of the garbage collection. Furthermore, if several requests are queued, they can all be processed together in one garbage collection, while if done separately they would each require their own garbage collection.

procedure+: flush-purification-queue!
Forces any pending queued purification requests to be processed. This examines the purify queue, and if it contains any requests, forces a garbage collection to process them. If the queue is empty, does nothing.

procedure+: print-gc-statistics
Prints out information about memory allocation and the garbage collector. The information is printed to the current output port. Shows how much space is "in use" and how much is "free", separately for the heap and constant space. The amounts are shown in words, and also in 1024-word blocks; the block figures make it convenient to use these numbers to adjust the arguments given to the `-heap' and `-constant' command-line options. Following the allocation figures, information about the most recent 8 garbage collections is shown, in the same format as a GC notification.

Note that these numbers are accurate at the time that print-gc-statistics is called. In the case of the heap, the "in use" figure shows how much memory has been used since the last garbage collection, and includes all live objects as well as any uncollected garbage that has accumulated since then. The only accurate way to determine the size of live storage is to subtract the value of `(gc-flip)' from the size of the heap. The size of the heap can be determined by adding the "in use" and "free" figures reported by print-gc-statistics.

(print-gc-statistics)
constant in use:   534121 words =   521 blocks +  617 words
constant free:        128 words =     0 blocks +  128 words
heap in use:        34845 words =    34 blocks +   29 words
heap free:         205530 words =   200 blocks +  730 words
GC #1: took: 0.13 (81%) CPU time, 0.15 (1%) real time; free: 207210
;No value

procedure+: set-gc-notification! [on?]
Controls whether the user is notified of garbage collections. If on? is given and #f, notification is enabled; otherwise notification is disabled. By default, notification is disabled.

The notification appears as a single line like the following, showing how many garbage collections have occurred, the time taken to perform the garbage collection and the free storage remaining (in words) after collection.

GC #5: took: 0.50 (8%) CPU time, 0.70 (2%) real time; free: 364346

To operate comfortably, the amount of free storage after garbage collection should be a substantial proportion of the heap size. If the percentage CPU time is consistently high (over 20%), you should consider running with a larger heap. A rough rule of thumb to halve the GC overhead is to take the amount of free storage, divide by 1000, and add this figure to the current value used for the `-heap' command-line option. Unfortunately there is no way to adjust the heap size without restarting Scheme.

procedure+: toggle-gc-notification!
Toggles GC notification on and off. If GC notification is turned on, turns it off; otherwise turns it on.


Go to the first, previous, next, last section, table of contents.