This chapter details Scheme 48’s user interface: its command-line arguments, command processor, debugger, and so forth.
A few command line arguments are processed by Scheme 48 as it starts up.
scheme48 [-i image] [-h heapsize] [-a argument ...]
> ,open os-strings > (define (f xs) (write (map os-string->string xs)) (newline) 0) ;must return an integer > ,build f foo.image > ,exit % scheme48vm -i foo.image -a mumble "foo x" -h 5000000 ("mumble" "foo x" "-h" "5000000") %
% (echo '#!/s48/install/prefix/lib/scheme48-1.9.2/scheme48vm -I' cat original.image) >new.image % chmod +x new.image
The usual definition of the s48 or scheme48 command is actually a shell script that starts up the Scheme 48 virtual machine with a -i imagefile specifying the development environment heap image and a -o vm-executable specifying the location of the virtual-machine executable (the executable is needed for loading external code on some versions of Unix; see section 8.4 for more information). The file go in the Scheme 48 installation source directory is an example of such a shell script.
When you invoke the default heap image, a command processor starts running. The command processor acts as both a read-eval-print loop, reading expressions, evaluating them, and printing the results, and as an interactive debugger and data inspector. See Chapter 3 for a description of the command processor.
We recommend running Scheme 48 under GNU Emacs or XEmacs using the cmuscheme48 command package. This is in the Scheme 48 distribution’s emacs/ subdirectory and is included in XEmacs’s scheme package. It is a variant of the cmuscheme library, which comes to us courtesy of Olin Shivers, formerly of CMU. You might want to put the following in your Emacs init file (.emacs):
(setq scheme-program-name "scheme48") (autoload 'run-scheme "cmuscheme48" "Run an inferior Scheme process." t)
The Emacs function run-scheme can then be used to start a process running the program scheme48 in a new buffer. To make the autoload and (require ...) forms work, you will also need to put the directory containing cmuscheme and related files in your emacs load-path:
(setq load-path (append load-path '("scheme-48-directory/emacs")))
Further documentation can be found in the files emacs/cmuscheme48.el and emacs/comint.el.
If you want to generally have your code run faster than it normally would, enter inline-values mode before loading anything. Otherwise calls to primitives (like + and cons) and in-line procedures (like not and cadr) won’t be open-coded, and programs will run more slowly.
The system doesn’t start in inline-values mode by default because the Scheme report permits redefinitions of built-in procedures. With this mode set, such redefinitions don’t work according to the report, because previously compiled calls may have in-lined the old definition, leaving no opportunity to call the new definition.
Inline-values mode is controlled by the inline-values switch. ,set inline-values and ,unset inline-values turn it on and off.
The ,dis command prints out the disassembled byte codes of a procedure.
> ,dis cons cons 0 (protocol 2) 2 (pop) 3 (make-stored-object 2 pair) 6 (return) >
The current byte codes are listed in the file scheme/vm/interp/arch.scm. A somewhat out-of-date description of them can be found in [5].
The command argument is optional; if unsupplied it defaults to the current focus object (##).
The disassembler can also be invoked on continuations and templates.
This section gives a brief description of modules and related entities. For detailed information, including a description of the module configuration language, see chapter 4.
A module is an isolated namespace, with visibility of bindings controlled by module descriptions written in a special configuration language. A module may be instantiated as a package, which is an environment in which code can be evaluated. Most modules are instantiated only once and so have a unique package. A structure is a subset of the bindings in a package. Only by being included in a structure can a binding be made visible in other packages. A structure has two parts, the package whose bindings are being exported and the set of names that are to be exported. This set of names is called an interface. A module then has three parts:
a set of structures whose bindings are to be visible within the module
the source code to be evaluated within the module
a set of exported interfaces
Instantiating a module produces a package and a set of structures, one for each of the exported interfaces.
The following example uses define-structure to create a module that implements simple cells as pairs, instantiates this module, and binds the resulting structure to cells. The syntax (export name ...) creates an interface containing name .... The open clause lists structures whose bindings are visible within the module. The begin clause contains source code.
(define-structure cells (export make-cell cell-ref cell-set!) (open scheme) (begin (define (make-cell x) (cons 'cell x)) (define cell-ref cdr) (define cell-set! set-cdr!)))
Cells could also have been implemented using the record facility described in section 5.9 and available in structure define-record-type.
(define-structure cells (export make-cell cell-ref cell-set!) (open scheme define-record-types) (begin (define-record-type cell :cell (make-cell value) cell? (value cell-ref cell-set!))))
With either definition the resulting structure can be used in other modules by including cells in an open clause.
The command interpreter is always operating within a particular package. Initially this is a package in which only the standard Scheme bindings are visible. The bindings of other structures can be made visible by using the ,open command described in section 3.4 below.
Note that this initial package does not include the configuration language. Module code needs to be evaluated in the configuration package, which can be done by using the ,config command:
> ,config (define-structure cells ...) > ,open cells > (make-cell 4) '(cell . 4) > (define c (make-cell 4)) > (cell-ref c) 4
A number of useful utilities are either built in to Scheme 48 or can be loaded from an external library. These utilities are not visible in the user environment by default, but can be made available with the open command. For example, to use the tables structure, do
> ,open tables >
If the utility is not already loaded, then the ,open command will load it. Or, you can load something explicitly (without opening it) using the load-package command:
> ,load-package queues > ,open queues
When loading a utility, the message "Note: optional optimizer not invoked" is innocuous. Feel free to ignore it.
See also the package system documentation, in chapter 4.
Not all of the the libraries available in Scheme 48 are described in this manual. All are listed in files rts-packages.scm, comp-packages.scm, env-packages.scm, and more-packages.scm in the scheme directory of the distribution, and the bindings they export are listed in interfaces.scm and more-interfaces.scm in the same directory.