

		  Notes on the Scheme User Interface
			     Chris Hanson


This document describes some of the procedures that are used to load
and run programs.  The procedures described here are not normally
called from programs -- they are designed for use by people typing at
Scheme's top level.

* Getting in and out of Scheme

Starting up the Scheme interpreter is somewhat system dependent, so
you should find out specifically how to do this from whoever maintains
Scheme at your site.  Usually, the program is invoked by typing

	scheme

at your operating system's command interpreter.  Scheme will load
itself, clear the screen, and print something like this:

	Scheme saved on Thursday June 11, 1987 at 6:59:33 PM
	  Release 5.1.0
	  Microcode 9.68
	  Runtime 13.71
	  SF 3.9

This information, which can be printed again by evaluating

	(identify-world)

tells you the following version information:

"Release" is the release number for the entire Scheme system.  Usually
we will increment this number every time we make a change in the
version of the system that is distributed to the outside world.
"Microcode" is the version number for the part of the system that is
written in C.  "Runtime" is the version number for the part of the
system that is written in Scheme.

Any other information following the above is version numbers for
specific subsystems.  "Beta" refers to the scode optimization program
SF, which is described below.  Other systems include the 6.001
student environment, the compiler, or the editor.

There are two ways you can leave the Scheme interpreter.  The first is
to evaluate

	(%exit)

which will halt the Scheme system.  Any information that was in the
interpreter is lost, so this should not be done lightly.

The other way is to suspend the interpreter.  When this is done you
may restart the interpreter where you left off.  Unfortunately this is
not possible in all operating systems -- currently it is known to work
on BSD Unix, Ultrix, and VMS.  It does NOT work on AT&T Unix or hp-ux.
The command for suspending is

	(quit)

If your system does not support suspension, this will have no effect,
otherwise Scheme will stop and you will be returned to the operating
system's command interpreter.

* The Read-Eval-Print Loop

When you first start up Scheme, 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 RETURN).  Scheme
evaluates the expression, prints the result, and gives you another
prompt.

** The prompt and level number

That 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 RETURN" after starting Scheme:

	1 ]=> foo

	Unbound Variable FOO

	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.
Meanwhile, any changes you make to this REPL will not affect the
original one.  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.

** Interrupts

This brings up the subject of interrupts.  This is a highly system
dependent topic, so I will discuss the implementation for Unix only.
You must find out the details from your system wizard for other
implementations.

Scheme has two interrupt keys under Unix (other systems may have more
than two): C-G and C-A.  The C-G key causes the current Scheme program
to stop immediately and returns you to the top level REPL.  C-A
prompts you for another character and performs some action based on
that character.  It is not necessary to type RETURN after C-G or C-A,
nor is it needed after the character that C-A will ask you for.  Here
are the more common options for C-A:

*** "I" means ignore the interrupt.  Type this if you made a mistake
and didn't really mean to type C-A.

*** "?" means print help information.  This will describe any other
options not documented here.

*** "Q" is similar to typing (%EXIT) at the REPL, except that it works
even if some program is running.

*** "Z" is similar to typing (QUIT) at the REPL, except that it works
even if some program is running.

*** "G" is identical to typing C-G.  Another way to get this effect is
to evaluate (ABORT-TO-TOP-LEVEL-DRIVER "").

*** "X" means abort whatever Scheme program is currently running and
return to the "current" REPL.  If no program is running, this just
causes another prompt to be printed.  Another way to get this effect
is to evaluate (ABORT-TO-NEAREST-DRIVER "").

*** "U" means abort whatever Scheme program is running and go up one
level.  If you are already at level number 1, it just stops the
program, leaving you at level 1.  Another way to get this effect is to
evaluate (ABORT-TO-PREVIOUS-DRIVER "").

*** "B" means suspend whatever Scheme program is running and start a
"breakpoint" REPL.  The program can be resumed by evaluating

	(proceed)

in that REPL at any time.

** PROCEED

Another way of exiting REPLs is to use the PROCEED procedure.  There
are two ways to use this procedure from inside an error REPL (usage
from other kinds of REPL is not necessarily the same):

*** (PROCEED) means to retry the expression that caused the error.
Unless you have done something to fix the error condition, this will
just cause the error to happen all over again.  In the example above
with the unbound variable FOO, the proper way to use PROCEED is to
first define FOO to have a value, then evaluate (PROCEED).  Your
program should then continue from that point normally.

One caveat: when you get an unbound variable error, the environment
for the REPL is the environment in which you looked up the variable,
which is not necessarily the same environment you wanted to define the
variable in.  It is best to use the %VE procedure to guarantee that
your definition goes into the right place.

*** (PROCEED <value>) means to return <value> in place of the
expression that caused the error.  Thus, if you cannot easily fix a
particular bug, but you know what the proper value for the expression
is, you can continue the computation this way.

** The current environment and syntax table

Every REPL has a "current" environment, which is the place where
expressions are evaluated, and definitions are stored.  When you start
up Scheme, this environment is the value of a variable called
USER-INITIAL-ENVIRONMENT.  There are a number of other environments in
the system, for example SYSTEM-GLOBAL-ENVIRONMENT (where all of the
Scheme system definitions are stored).

You can get the current environment by evaluating

	(rep-environment)

Also, if you have a compound 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.
When an error occurs, the error REPL that is created is usually
initialized so that its current environment is the one in which the
error occurred.  Sometimes it is useful to change the current
environment to another value, and there are two ways to do this:

*** (%VE <environment>) will temporarily Visit an Environment.  This
makes the current environment be <environment>.  While you are
visiting that environment, the prompt is changed to the string

	Visiting->

You can get back to the previous environment for this REPL by using
the interrupt C-A X.

*** (%GE <environment>) will permanently Go to an Environment.  This
is like %VE except that the previous environment is forgotten and the
interrupt characters do not change the current environment.

The argument to either %VE or %GE is allowed to be a compound
procedure as well as an environment object.  If it is a compound
procedure, then the closing environment for that procedure is the new
environment.

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, often you will 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.  The (%GST <syntax-table>) procedure allows you to do that.

* Files and loading

To load files of Scheme code, use the procedure LOAD, as described in
R^3RS.  MIT Scheme extends the definition of LOAD in several ways:

** The first argument to LOAD may be a list of filenames rather than a
single filename, in which case it loads them all in order.

** There is an optional second argument which specifies the
environment in which the file is to be loaded.

** 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".

** The variable LOAD-NOISILY?, if set to true, will cause the value of
each expression in the file to be printed as it is evaluated.
Otherwise, nothing is printed except for the value of the last
expression in the file.  The procedure LOAD-NOISILY provides the same
effect independent of the value of this flag.  (Note: the noisy
loading feature is implemented for source code files only.)

** If the pathname given to LOAD does not specify the type or version
of the file, it tries the following files in this order (examples are
in Unix syntax):

	1.  The exact name given			"<name>"
	2.  Type = "bin", no version			"<name>.bin"
	3.  Type = "bin", greatest version number	"<name>.bin.0"
	4.  Type = "scm", no version			"<name>.scm"
	5.  Type = "scm", greatest version number	"<name>.scm.0"

All filenames are interpreted relative to a working directory, which
is normally initialized to the default directory at the time the
interpreter was started.  (Note that on hp-ux, there is a bug which
makes this difficult to do, so the working directory is initialized to
your home directory.)  The working directory can be obtained or
modified with the following procedures:

	(WORKING-DIRECTORY-PATHNAME)
	(SET-WORKING-DIRECTORY-PATHNAME! <new-working-directory>)

For typing convenience, there are aliases for these procedures, called
%PWD and %CD, respectively.  The long versions of the names are
intended to be used in programs, the short names for interactive use.

WORKING-DIRECTORY-PATHNAME always returns a pathname which has no
name, type, or version components.  SET-WORKING-DIRECTORY-PATHNAME!,
if given a pathname with name/type/version components, will convert it
into a pathname of the former type by adding those components to the
end of the directory specification.  Thus, under Unix,

	(SET-WORKING-DIRECTORY-PATHNAME! "/foo/bar")

returns the pathname "/foo/bar/" as its value.

* World Images

Scheme provides support for saving and restoring entire world images,
in two different ways.  The first method writes a file containing all
of the Scheme code in the world, which is called a "band".  The file
"runtime/scheme.bin" which is loaded by the microcode is just such a
band.  To make your own band, use the procedure DISK-SAVE:

	(DISK-SAVE <filename>)

	or

	(DISK-SAVE <filename> <identify>)

Calling this procedure causes a band to be written into the specified
file.  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.

** If <identify> is a string, do the same thing except print that
string instead of "Scheme" when restarting.

** If <identify> is the constant #T, it means 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.

To restore a saved band, use the "-band" argument to Scheme when it is
started, or else use the procedure (DISK-RESTORE <filename>) from a
running Scheme, which will destroy the current world, replacing it
with the saved world.  DISK-RESTORE's argument may be omitted, in
which case it defaults to the filename from which the current world
was last restored.

An alternative method for saving the world is the DUMP-WORLD
procedure, which accepts the same arguments as DISK-SAVE, and works in
much the same way.  However, rather than dumping a band, DUMP-WORLD
saves an executable image, which you start up in the normal (operating
system dependent) way.  This has the advantage of being considerably
faster to start on some systems, but such an image typically takes a
factor of 2 or more in disk space than the corresponding band.

* SF (Syntax File)

SF is the program which transforms source code files into binary SCode
form.  It performs numerous optimizations which can make your programs
run considerably faster.  Also, binary files load very quickly
compared to source files.

The simplest way to use SF is just to say:

	(SF <filename>)

This will cause your file to be transformed, and the new binary file
to be written out with the same name, but with pathname-type "bin".
If you do not specify a pathname-type on the input file, "scm" is
assumed.  Version numbers are preserved, that is, if the input file
has a version number, the output file will have the same version
number.

Like LOAD, the first argument to SF may be a list of filenames instead
of a single filename.

SF takes an optional second argument, which is the filename of the
output file.  If this argument is just a directory, then the output
file has its normal name but uses that directory instead.

SF takes an optional third argument, which if given, causes an extra
file to be written containing some information about the compilation
of your file.  The third argument is a filename, which is treated just
like the second argument.  Currently this is not too useful, but when
SF is connected to the native code compiler it will produce
considerably more information.

If either the second or third argument is the empty string, the normal
default filename is used.

By default the information file is written to the same directory as
the output file, except that the pathname-type is "unf".  If you want
information files to be generated all the time, set the variable SFU?
to true -- otherwise they will not be generated unless you supply a
third argument to SF.

Several declarations can be added to your program to help SF make it
more efficient.  Normally, all files have a line

	(DECLARE (USUAL-INTEGRATIONS))

near their beginning, which tells SF that free variables whose names
are defined in SYSTEM-GLOBAL-ENVIRONMENT will not be shadowed by other
definitions when the program is loaded.  If you redefine some
global name in your code, for example CAR, you should indicate it in
the declaration:

	(DECLARE (USUAL-INTEGRATIONS CAR CDR CONS))

Currently, the names which this declaration affects are (this WILL
change in the future):

* + - -1+ / 1+ < <= = > >= APPLY ASCII->CHAR ASSQ
BIT-STRING->UNSIGNED-INTEGER BIT-STRING-ALLOCATE BIT-STRING-AND!
BIT-STRING-ANDC! BIT-STRING-CLEAR! BIT-STRING-FILL!
BIT-STRING-LENGTH BIT-STRING-MOVE! BIT-STRING-MOVEC! BIT-STRING-OR!
BIT-STRING-REF BIT-STRING-SET! BIT-STRING-ZERO?  BIT-STRING=?
BIT-STRING?  BIT-SUBSTRING-MOVE-RIGHT! CAAAAR CAAADR CAAAR CAADAR
CAADDR CAADR CAAR CADAAR CADADR CADAR CADDAR CADDDR CADDR CADR CAR
CDAAAR CDAADR CDAAR CDADAR CDADDR CDADR CDAR CDDAAR CDDADR CDDAR
CDDDAR CDDDDR CDDDR CDDR CDR CEILING CELL-CONTENTS CELL?  CHAR->ASCII
CHAR->INTEGER CHAR-ASCII?  CHAR-BITS CHAR-CODE CHAR-DOWNCASE
CHAR-UPCASE CONS CONS* COS EIGHTH EMPTY-STREAM?  EQ?  ERROR-PROCEDURE
EXP FALSE FALSE?  FIFTH FIRST FLOOR FORCE FOURTH GENERAL-CAR-CDR
GET-FIXED-OBJECTS-VECTOR HEAD IDENTITY-PROCEDURE INTEGER->CHAR
INTEGER-DIVIDE INTEGER-DIVIDE-QUOTIENT INTEGER-DIVIDE-REMAINDER LENGTH
LEXICAL-ASSIGNMENT LEXICAL-REFERENCE LEXICAL-UNASSIGNED?
LEXICAL-UNBOUND?  LEXICAL-UNREFERENCEABLE?  LIST LIST->VECTOR
LOCAL-ASSIGNMENT LOG MAKE-BIT-STRING MAKE-CELL MAKE-CHAR
MAKE-NON-POINTER-OBJECT MAKE-OBJECT-DANGEROUS MAKE-OBJECT-SAFE
MAKE-STRING MEMQ NEGATIVE?  NOT NULL?  OBJECT-DANGEROUS?  PAIR?
POSITIVE?  PRIMITIVE-DATUM PRIMITIVE-PROCEDURE-ARITY
PRIMITIVE-SET-TYPE PRIMITIVE-TYPE PRIMITIVE-TYPE?  QUOTIENT READ-BITS!
REMAINDER ROUND SCODE-EVAL SECOND SET-CAR! SET-CDR!
SET-CELL-CONTENTS! SET-INTERRUPT-ENABLES! SET-STRING-LENGTH!
SEVENTH SIN SIXTH SQRT STRING->SYMBOL STRING-ALLOCATE STRING-HASH
STRING-LENGTH STRING-MAXIMUM-LENGTH STRING-REF STRING-SET! STRING?
SUBSTRING-CI=?  SUBSTRING-DOWNCASE! SUBSTRING-FIND-NEXT-CHAR-IN-SET
SUBSTRING-FIND-PREVIOUS-CHAR-IN-SET SUBSTRING-MATCH-BACKWARD
SUBSTRING-MATCH-BACKWARD-CI SUBSTRING-MATCH-FORWARD
SUBSTRING-MATCH-FORWARD-CI SUBSTRING-MOVE-LEFT! SUBSTRING-MOVE-RIGHT!
SUBSTRING-UPCASE! SUBSTRING<?  SUBSTRING=?  SUBVECTOR->LIST
SYSTEM-GLOBAL-ENVIRONMENT SYSTEM-HUNK3-CXR0 SYSTEM-HUNK3-CXR1
SYSTEM-HUNK3-CXR2 SYSTEM-HUNK3-SET-CXR0! SYSTEM-HUNK3-SET-CXR1!
SYSTEM-HUNK3-SET-CXR2! SYSTEM-LIST-TO-VECTOR SYSTEM-PAIR-CAR
SYSTEM-PAIR-CDR SYSTEM-PAIR-CONS SYSTEM-PAIR-SET-CAR!
SYSTEM-PAIR-SET-CDR! SYSTEM-PAIR?  SYSTEM-SUBVECTOR-TO-LIST
SYSTEM-VECTOR-REF SYSTEM-VECTOR-SET! SYSTEM-VECTOR-SIZE
SYSTEM-VECTOR?  THIRD TRUE TRUNCATE UNSIGNED-INTEGER->BIT-STRING
VECTOR VECTOR-8B-FILL! VECTOR-8B-FIND-NEXT-CHAR
VECTOR-8B-FIND-NEXT-CHAR-CI VECTOR-8B-FIND-PREVIOUS-CHAR
VECTOR-8B-FIND-PREVIOUS-CHAR-CI VECTOR-8B-REF VECTOR-8B-SET!
VECTOR-CONS VECTOR-LENGTH VECTOR-REF VECTOR-SET!
WITH-HISTORY-DISABLED WITH-INTERRUPT-MASK WITH-INTERRUPTS-REDUCED
WITH-THREADED-CONTINUATION WRITE-BITS! ZERO?

Another useful facility provided by SF is the ability to in-line code
procedure definitions.  In fact, SF will perform full beta conversion,
with automatic renaming, if you request it.  Here are the relevant
declarations:

	(DECLARE (INTEGRATE <name1> <name2> ...))

The variables <name1> etc. should be defined in the same file as this
declaration.  Any references to those names, in the same block as the
declaration, will be replaced by the code from the definition.

	(DECLARE (INTEGRATE-OPERATOR <name1> <name2> ...))

This is like the INTEGRATE declaration, except that it only
substitutes for references that appear in the operator position of a
combination.  All other references are ignored.

Note that the most common use of this facility, in-line coding of
procedure definitions, requires a somewhat complicated use of these
declarations.  There should be an INTEGRATE-OPERATOR declaration for
the procedure's name, and (internal to the procedure's definition) an
INTEGRATE declaration for each of the procedure's parameters.  For
example,

	(DECLARE (INTEGRATE-OPERATOR FOO-BAR))

	(DEFINE FOO-BAR
	  (LAMBDA (FOO BAR)
	    (DECLARE (INTEGRATE FOO BAR))
	    (VECTOR-REF (VECTOR-REF FOO BAR) 3)))

The reason for this complication is as follows: the INTEGRATE-OPERATOR
declaration finds all the references to FOO-BAR and replaces them with
the lambda expression from the definition.  Then, the INTEGRATE
declarations take effect because the combination in which FOO-BAR
occurred supplies specifies code which is substituted throughout the
body of the procedure definition.  For example:

	(FOO-BAR (CAR BAZ) (CDR BAZ))

First use the INTEGRATE-OPERATOR declaration:

	((LAMBDA (FOO BAR)
	   (DECLARE (INTEGRATE FOO BAR))
	   (VECTOR-REF (VECTOR-REF FOO BAR) 3))
	 (CAR BAZ)
	 (CDR BAZ))

Next use the internal INTEGRATE declaration:

	((LAMBDA (FOO BAR)
	   (VECTOR-REF (VECTOR-REF (CAR BAZ) (CDR BAZ)) 3))
	 (CAR BAZ)
	 (CDR BAZ))

Next notice that the variables FOO and BAR are not used, and eliminate
them:

	((LAMBDA ()
	   (VECTOR-REF (VECTOR-REF (CAR BAZ) (CDR BAZ)) 3)))

Finally, remove the ((LAMBDA () ...)) to produce

	(VECTOR-REF (VECTOR-REF (CAR BAZ) (CDR BAZ)) 3)

* GNU Emacs interface

There is an interface library, called "xscheme", distributed with GNU
Emacs, which facilitates running Scheme as a subprocess of Emacs.  We
apologize for the fact that this interface has several serious bugs --
they will be fixed soon.

To invoke Scheme from Emacs, use M-X run-scheme, which is defined when
the library "scheme" is loaded.  You can also give run-scheme a prefix
argument, in which case it will allow you to edit the command line
which is used to invoke Scheme.  DO NOT remove the "-emacs" option!

Scheme will be started up as a subprocess in a buffer called
"*scheme*".  This buffer will be in scheme-mode and all output from
the Scheme process will go there.  Also, the mode line will be changed
to have information like the following in it between the filename and
the mode information:

	I 1 [Normal REP]

The first field is a "run light", which indicates the run-status of
the Scheme process.  It can be "I", indicating that Scheme is waiting
for input, or "R" meaning that Scheme is running, or "G" meaning that
Scheme is garbage collecting.

The second field is the level number.

The third field describes the type of REPL that is running.  Other
values include:

	[Error REP]
	[Breakpoint REP]
	[Debugger]
	[Environment Inspector]

When "xscheme" is loaded, scheme-mode is extended to include commands
for evaluating expressions:

** M-o (xscheme-send-buffer) evaluates the current buffer.  This has
no effect in the "*scheme*" buffer.

** M-z (xscheme-send-definition) evaluates the current definition.

** M-C-Z (xscheme-send-region) evaluates the current region.

** M-RET (xscheme-send-previous-expression) evaluates the expression
to the left of point.  This is also bound to C-c p and C-x C-e.

** C-c n (xscheme-send-next-expression) evaluates the expression to
the right of point.

** C-c C-y (xscheme-yank-previous-send) yanks the last text that was
evaluated.

Also, the following commands provide interrupt capability:

** C-c g (xscheme-send-control-g-interrupt) is like typing C-G when
running Scheme without Emacs.

** C-c x (xscheme-send-control-x-interrupt) is like typing C-A X.

** C-c u (xscheme-send-control-u-interrupt) is like typing C-A U.

** C-c b (xscheme-send-breakpoint-interrupt) is like typing C-A B.
