Scheme libraries

As real-world programmers develop large software systems, they commonly find that certain subproblems (such as sorting, line-at-a-time input and output, and the implementation of more advanced data structures like hash tables and priority queues) commonly recur. Sensible programmers naturally prefer to write up one careful and exact solution to a recurring subproblem and to store it so that it can easily be reloaded, rather than repeatedly writing a new solution, or a new version or copy of the solution, for each recurrence of the subproblem. A library is a collection of such solutions.

The design of the Scheme programming language promotes the development and use of libraries. From the point of view of the language, a library is a program that happens to consist entirely of definitions. One can, in effect, extend the language to include the procedures that are defined in a library simply by loading the file in which the library is stored; no special steps are required to merge or link the file thus loaded with the Scheme interactive interface.

In a company that develops and sells software, the procedure library (or at least the source code from which it is compiled) is usually a secret; only employees of the company may see and use it. However, Scheme programmers working in academic settings sometimes make their libraries available. A sampling of what is available can be found in the Internet Scheme Repository at Indiana University.

As an example, let's look at one very popular library: SLIB, compiled and edited by Aubrey Jaffer. Though copyrighted, SLIB is available without charge over the Internet. It is available on MathLAN in the directory /usr/local/lib/slib. The SLIB manual is accessible on the World Wide Web, beginning at http://www-swiss.ai.mit.edu/~jaffer/slib_toc.html.

SLIB is not written entirely in standard Scheme. Some of the contributions use added features that differ slightly from one Scheme implementation to another or are not provided at all by some versions of Scheme. Each SLIB user is therefore encouraged to start by loading a configuration file for his or her particular Scheme system; the configuration file conceals these differences by adding appropriate definitions for missing procedures and redefining others so that they match the expectations of the SLIB libraries. The configuration file for Chez Scheme is chez.init.


Exercise 1

Start Scheme and have it load in the configuration file. If you're starting Scheme in an dtterm window, you can do this by adding the name of the configuration file to the command line. Alternatively, either in dtterm or in an XEmacs window, you can call the load procedure to bring in the file.


The source code in the SLIB library is divided into a large number of files, but it is actually easier to understand the organization of SLIB by thinking of it as a collection of optional features that can be added to standard Scheme. Once the configuration file has been loaded, you can get a list of the features that are available in SLIB by evaluating the expression (map car *catalog*). (*Catalog* is an association list that SLIB uses internally; the keys are the features supplied, and the values are mostly the names of the files in which those features are implemented.)


Exercise 2

Exactly one of the symbols replicate, tree, and boolean-functions designates a feature that is provided by SLIB. Find out which one.


The configuration file also arranges for a non-standard procedure named require to be defined. The require procedure takes a symbol as argument; when invoked, it looks up the symbol in *catalog* and opens and loads in the file that supplies the feature -- unless it has previously been loaded, in which case that step is omitted. Sometimes one SLIB source-code file presupposes another; the require procedure ensures that all the necessary components are loaded and that none of them is loaded more than once.

Here's a simple example of the use of an SLIB procedure. Mail-order companies and other businesses that take customers' names by telephone sometimes have trouble with misspellings of names. If a customer's name is recorded incorrectly on one document, such as an order form, it may be difficult to match that document up with others on which the name is correctly spelled, such as a payment voucher. To make it easier to recover from such a mismatch, such companies sometimes add to their internal documents a four-character ``Soundex'' code, derived from the name, that is often identical for differently spelled variants of a name. For instance, Schultz and Shults have the same Soundex code (S432); so do Berowne and Braun (B650), and Macleod and McCloud (M243).

One of SLIB's features is soundex; if you enter the expression (require 'soundex), SLIB will load all the procedures necessary to define a procedure, also called soundex, that takes any string as argument and delivers a Soundex code for it.


Exercise 3

Determine the Soundex code for your last name and the Soundex code for any of the various misspellings of your last name that correspondents have perpetrated.


Exercise 4

Using a different feature of SLIB, find the prime factors of 1522301997.


Since SLIB is provided in the form of source-code files, one can examine them to study exactly what the library procedures do, how they do it, and how real-world Scheme programmers use the language. You'll find all of the library files in the /usr/local/lib/slib directory; the file names end in .scm.

Short-form procedure definitions

Some of the SLIB source-code files make use of an optional syntactic construction that I've avoided so far in this course: In defining a procedure by associating the identifier with the value of a lambda-expression, one can abbreviate the definition by enclosing the procedure identifier and the elements of the parameter list in parentheses and omitting the lambda. For instance, instead of writing

(define square
  (lambda (n)
    (* n n)))

one could write

(define (square n)
  (* n n))

so that one would have slightly fewer lines of text and pairs of parentheses to worry about. The two forms of procedure definition are completely equivalent; the choice of one or the other is a matter of personal style and preference.

Definitions of variable-arity procedures also have short forms. For instance,

(define writeln
  (lambda args
    (for-each display args)
    (newline)))

has the short form

(define (writeln . args)
  (for-each display args)
  (newline))

and

(define average
  (lambda (first . rest)
    (/ (+ first (apply + rest)) (+ 1 (length rest)))))

has the short form

(define (average first . rest)
  (/ (+ first (apply + rest)) (+ 1 (length rest))))

Exercise 5

Examine one or more of the SLIB course files and choose one to study carefully. (If you can't decide, strcase.scm might be a good choice.) What features of the author's programming style make the code more readable and seem to be worth emulating? What features make it harder to read and understand the code?


This document is available on the World Wide Web as

http://www.math.grin.edu/courses/Scheme/spring-1998/libraries.html

created April 30, 1997
last revised June 21, 1998

John David Stone (stone@math.grin.edu)