Wraith Scheme Help File

Main Window

Wraith Scheme Help File

Copyright © 1988, 1989, 1990, 1991, 2006, 2007, 2008, 2009 Jay Reynolds Freeman, all rights reserved.
Personal Web Site: http://web.mac.com/Jay_Reynolds_Freeman
EMail: Jay_Reynolds_Freeman@mac.com.

NOTICE:

If you can't find what you are looking for in the table of contents, use the "Find" command -- in either the Apple Help Viewer or your HTML browser, whichever you are using to view this file -- to locate words and phrases.

Table of Contents:

Introduction:

Wraith Face

Welcome to the help file for Wraith Scheme, an implementation of the Scheme programming language for the Apple Macintosh™. Wraith Scheme was written by me, Jay Reynolds Freeman. By all means Email me about it if you wish.

I believe Wraith Scheme is a complete implementation of the "R5" dialect of Scheme (major Revision 5 of Scheme). There is one caveat to the word "complete": The R5 report (citation in next paragraph) describes a number of optional Scheme features, using language like "some implementations support ...", or something similar. Wraith Scheme does not support all of these optional features. A list of optional features that are missing is here.

This document is not a complete Scheme language description or programming manual. For a complete and authoritative manual, I strongly recommend that you obtain and peruse a copy of the 1998 Revised5 report on the Algorithmic Language Scheme, edited by Richard Kelsey, William Clinger and Jonathan Rees. That report is available on several Internet sites, such as http://www.schemers.org.

You might also consider reading some of the Scheme References and Lisp References listed later herein.

Wraith Scheme is shareware: You are welcome to use Wraith Scheme for free, forever, and to pass out free copies of it to anybody else. If you should at some time wish to make a shareware donation for Wraith Scheme, use my PayPal&trade account or send a check by regular mail to

Jay Reynolds Freeman
Post Office Box 60628
Palo Alto, CA, 94306-0628
U. S. A.

PayPal will need my EMail address:

Jay_Reynolds_Freeman@mac.com

How much to donate is your choice.

Wraith Scheme was named after my late, lamented, scruffy gray cat, "Wraith". If you don't think that makes sense, remember that it runs on a computer named after a raincoat. Wraith Scheme is a direct descendent of Pixie Scheme (another cat), which I wrote in the late 1980s for early versions of the Apple Macintosh™.

Getting Started:

By all means, read through this material and the next section or two following it, but you might also want to look at the section, Common Problems and Solutions.

System Requirements:

Wraith Scheme is a stand-alone application for the Apple Macintosh&trade. It is universal binary, and thus should run on any Macintosh with either an Intel microprocessor such as the Core Duo&trade, or one of the older PowerPC&trade microprocessors. Wraith Scheme requires the Apple MacOS operating system, version 10.4 or later. Its memory and disc requirements are minimal: The program occupies less than 5 MBytes (MegaBytes) of space on disk, requires about 30 MBytes of memory to run with its default "preferences" settings, and can run usefully while using less than 10 MBytes of memory.

Installation:

An installation of Wraith Scheme comprises just the "Wraith Scheme" application itself -- there are no extra files. The Wraith Scheme application contains some extra items embedded within it, such as HTML help files (including this one), a "README" file, and some examples of Scheme source code, so that all you really need is the application. (By the way, in case you obtained this help file as a separate download, the "Wraith Scheme Help" menu item, in Wraith Scheme's "Help" menu, will call up this same file from within the program -- you don't need a separate copy.)

"Installation" is simply the act of putting the application wherever you like. Possibly it should end up in your "Applications" folder, but that choice is up to you.

Wraith Scheme is what might be called "classic shareware": It depends solely on your generosity for support, with no strings attached. In particular, there is nothing to register, there are no activation codes required, and there are no enhanced versions available for a price. The shareware product, "Wraith Scheme", is all there is. Furthermore, Wraith Scheme will not emit annoying reminders to send me a shareware donation.

You are welcome to make as many backup copies of Wraith Scheme as you wish, and to give free copies of it to anyone.

Security:

Most people consider it ill-advised to run an unknown application -- like Wraith Scheme -- without special precautions, because it might contain code to do something malicious. If I had deliberately written a malicious program, I certainly wouldn't tell you, at least, not until it was way too late. What's more, if you are a suspicious type -- and in today's Internet and computing environment, you should be! -- there is nothing I can do or say to convince you that I have not put some ill-intended code into Wraith Scheme. Actually, I suppose it might help if I told you where I live, but I myself am a suspicious type, so I am not going to do that.

Besides, my house is a mess.

It might be useful to remember that Apple's MacOS X operating system is based on Unix: If you have moderate Unix experience, you might know that Unix is pretty good about keeping one user from messing with other users' data. Thus you might create a special, "dummy", user account, just for testing Wraith Scheme, with access to nothing other than Wraith Scheme and any files of Scheme code you may be using. If you know how to do that, good. If not, perhaps you should seek advice from a Unix-knowledgeable and trustworthy friend. (You shouldn't rely on me to provide the details; for all you know I am a computer criminal who might deliberately tell you something that didn't work and thereby set you up for disaster.)

Furthermore, one thing I worry about -- something every software developer worries about -- is that some third party will modify my code to be malicious, or create a malicious program with the same name and appearance as mine, and produce nefarious results thereby. I have no way to avoid this problem; nobody does.

Starting Wraith Scheme:

Just click on the Wraith Scheme icon, and away you go. The program will open up a window that looks like this:

Main Window

The Wraith Scheme Main Window, at reduced size.

In case you can't read the image on your browser, the messages shown at startup will be something like:

The "Top-level loop..." message means that Wraith Scheme has completed initialization and started doing what a Scheme interpreter does -- running an endless loop of reading Scheme code that you type in, processing (more precisely, "evaluating") what it read, and printing out the results.

Wraith Scheme Startup Actions:

On startup, Wraith Scheme

Changing the Startup Defaults:

All of Wraith Scheme's preferences take effect at startup, so as you learn later herein what those preferences are, remember that you can change Wraith Scheme's startup behavior by changing them.

In particular, you might write your own file to be loaded on initialization, and set the preferences to load it. Such a file might contain text like:

(By the way, Scheme source files do not have to end in ".s". That is merely a personal convention of my own.)

Alternatively, the file could load a Wraith Scheme world that you had previously saved.

Perhaps you would not like to have any file loaded at all at startup -- maybe you are sick of seeing the demonstration program run. In that case, delete the text in the "Load This Source File After Startup" field in the preferences window, so that it looks like this:

Preferences Window, blank file field

Changing How it Looks:

If you don't like the way the Wraith Scheme main window looks, there are plenty of ways to change its appearance. There is all the usual Macintosh stuff for customizing the user interface, and in particular:

Interacting with Wraith Scheme:

While you are reading this section, remember that there is also a section called Common Problems and Solutions.

Wraith Scheme provides one main window, a few buttons, and a generous handful of menu items. The main part of the Wraith Scheme Window is where you do almost everything with the Wraith Scheme program -- things like entering Scheme source code, running it, and looking at the results. The buttons, menu items, and a few accessory panels -- Apple calls them "drawers" -- that slide out from the main window allow you to do things to the Wraith Scheme program -- things like setting options and taking control of Scheme programs that are misbehaving. They also allow you to keep track of what Wraith Scheme is doing.

There is one other way of interacting with Wraith Scheme that may be particularly useful: Wraith Scheme makes considerable use of "tooltips" -- the brief text descriptions that pop up when the cursor is positioned over particular areas of the screen. You can learn something about almost any visible feature of Wraith Scheme by moving the cursor over it and waiting for a tooltip to appear.

Note that Wraith Scheme requires ASCII characters for everything it does. (ASCII characters are pretty much the letters of the English alphabet and the standard punctuation marks -- what you could get from the keyboard of an old-fashioned typewriter.) That requirement includes the names of files and folders that Wraith Scheme might have to deal with, and in the case of files, it means that Wraith Scheme will complain if the folder containing the file has a name containing non-ASCII characters, or if the folder containing that folder does, and so on.

Let's discuss the window, buttons, and menu items in more detail:

The Wraith Scheme Window:

Main Window

The Wraith Scheme Main Window, at reduced size.

Mostly, you type Wraith Scheme commands into the Wraith Scheme window, and look there to see what happened.

The Input Panel:

Input Panel

The left end of the Input Panel, full size.

You type into the panel at the bottom of the window that is one line tall and almost as wide as the whole window. That panel is surrounded by black lines. Input to Wraith Scheme is line-at-a-time. Wraith Scheme will process an entire line when you press the "return" key. If you are typing a Scheme expression that takes several lines and notice a mistake after you have already pressed the "return" key for that line, you can press the "Discard Input" button, or use the corresponding menu item in the Interpreter Menu, to start over.

You do not need to have the cursor at the right end of the line when you press the "return" key. Wraith Scheme will get to process the entire line when you press "return", no matter where the cursor is positioned in the line.

The one-line panel where you type provides standard Apple text-editing capability, including cut-and-paste and drag-and-drop. It is in fact a scrolling window, though there is no scroll bar to tell you so, and only one line of its text will be visible at any given time. You may use the up-arrow and down-arrow keys to scroll back and forth among lines of text that you have previously typed. For convenience, there are buttons labeled "Previous Command" and "Subsequent Command" that also scroll this window.

If you type a single line -- with no "return" -- that is longer than the Input Panel is wide, the line will "wrap", and you will only see the last part of it in the Input Panel. Don't worry. It's all there, and you can use the keys to move back and forth in a line to get to the first part of it, if necessary. Wraith Scheme will finally "see" the entire line, and start to process it, when you get around to pressing the "return" key.

When you have scrolled to a line that you previously typed, and have the cursor on that line, you may press "return" to send that line of text to Wraith Scheme again. You can re-enter a Scheme expression that spanned more than one line, one line at a time: Use the scroll commands to retrieve the first line of the expression, press "return", use the arrow keys to retrieve the second line of the expression, press "return", and so on.

The Macintosh's "cut-and-paste" and "drag-and-drop" mechanisms are very useful for entering Scheme expressions.

Although you can only edit one line of text in the Wraith Scheme window, Scheme commands may span more than one line. For example if you type (with a final "return")

the effect is the same as if you had typed (again with a final return)

That is, Wraith Scheme prints out

The Main Display Panel:

MainDisplayPanel

The Main Display Panel, at reduced size.

The Main Display Panel is the big panel that covers most of the Wraith Scheme window. It shows copies of the text that you have submitted to Wraith Scheme, interspersed with whatever Wraith Scheme has printed out in response. You cannot edit that text, but you can select it for cut-and-paste or drag-and-drop to some other location, such as the Wraith Scheme Input Panel. The Main Display Panel scrolls too, using the scroll bar at the right edge of the main window.

Both the input window and the main display window can store essentially unlimited amounts of scrolled-back text, but if for some reason you want to reduce the amount of scroll-back, there is a "Trim Scrollback" menu item in the Interpreter Menu, that does so. Every time you use it, it trims off the oldest half of scrolled text in each window, down to 6000 characters. That is, this command will never reduce the amount of scrolled-back text in either window to less than 6000 characters.

The Message Panel:

The Message Panel is the top line of the Wraith Scheme window. Wraith Scheme will occasionally print messages there, that tell something about what the Wraith Scheme program is doing. One message that you will probably see a lot is "Garbage collection completed." Any message printed will go away after about ten seconds.

Message and Dialog Panels

The Message and Dialog Panels, slightly reduced.

The Dialog Panel:

The dialog panel consists of the second and third lines from the top of the Wraith Scheme window, which are isolated from the rest of the window by a horizontal line beneath them. Wraith Scheme will start a dialog with you by printing a prompt message in the first line of the panel, and will then move the cursor to the start of the second line of the panel and wait for you to enter your reply -- one line only. Type the line, using the same line-editing commands as for the main window, and type a final "return" when you are done.

As a visual cue that a dialog is in progress, the prompt message will display in colored text, cycling through several colors, to draw your attention to the fact that Wraith Scheme is waiting for you to do something.

You don't actually need to type a response: You may use cut-and-paste or drag-and-drop to make your response, so long as it's just one line long.

To remind you of what has been going on, Wraith Scheme will leave the text of the last dialog visible in the dialog panel, with the prompt message in the normal color, until the next dialog begins.

In a typical dialog, Wraith Scheme might ask you the name of a file to load.

The Basic Buttons Drawer:

Basic Buttons Drawer

The Basic Buttons Drawer, full size.

The Basic Buttons Drawer slides out from the left side of the Wraith Scheme window. You make the drawer open and close with the "Show Basic Buttons" menu item in the Window Menu, or you can drag the left edge of the drawer with the mouse to slide it in and out. Its buttons do the following things:

The Basic Buttons drawer contains one more useful item, but it is not a button. Near the bottom edge of the drawer, close to the left end of the Input Panel, is a small text field that is normally invisible because it contains no text. When you are entering a Scheme expression that takes more than one line, this field will contain text to remind you of how many right parentheses you need to complete the expression, if any, or if you are in the process of typing a text string that spans more than one line, it will remind you that you need a quotation mark (") to complete the string. I put this feature in because many times I have sat bewildered in front of a Lisp or Scheme interpreter, wondering why the command I had just typed wasn't doing anything, without realizing that I had to type something else to finish it.

Thus if you type the following line into the input panel -- note the unbalanced parentheses -- followed by "return":

The little field at the bottom of the Basic Buttons drawer will remind you:

Here are some images that show this field in operation:

Expect Right Parenthsis

Expect Quotation Mark

Wraith Scheme will remind you when what you have typed has unbalanced parentheses or a missing quotation mark. (Images shown full size.)

The basic buttons drawer is set up so that if you close it part way, the edges of the buttons remain visible, and the little reminder field at the bottom also remains visible. Thus, once you have enough experience with Wraith Scheme to know which button is which without reading the label on it, you can save space on your display by closing the basic buttons drawer most of the way, and still use all of its features.

The Wraith Scheme Instrument Panel:

Instrument Panel

The Wraith Scheme Instrument Panel, slightly reduced.

The Wraith Scheme Instrument Panel is a drawer that slides out from the bottom of the Wraith Scheme window. You make the drawer open and close with the "Show Instrument Panel" menu item in the Window Menu, or you can drag the bottom of the drawer with the mouse to slide it in and out.

The instrument panel contains no buttons or other controls; all it does is display some information about what Wraith Scheme is up to and what it has been doing. Many of the items displayed are self-explanatory; the meanings of the others are described elsewhere herein. Don't forget to move the cursor over items to read the tooltips associated with them.

In particular, the instrument panel shows the names of the last world file loaded, and of the last file of Scheme source code loaded. To see the complete path for either of these items, move the cursor over the file name, and the full path will pop up as a tooltip.

Several of the items displayed in the instrument panel are "status lights", that go on and off when the item whose status they monitor changes. If you don't think these are useful, I at least hope you think they are cute. Every computer ought to have status lights, preferably ones that blink a lot ...

When Wraith Scheme is busy, the instrument panel display will lag behind what Wraith Scheme is doing, but it will catch up when it gets the chance.

The instrument panel is set up so that if you close it part way, the items at the bottom of the panel are covered up, and the items at the top of the panel remain visible. I have put what I believe are the most important items in the instrument panel at the top. Thus, if you want to save space on your display, you can close the instrument panel most of the way and still see the most useful information that it contains.

When the Basic Buttons Drawer and Instrument Panel are both partially closed, the Wraith Scheme Main Window might look like the image that follows. Note that there is still enough of the buttons visible to click on them:

Main Window Partial Drawers

The Wraith Scheme Main Window, with Basic Buttons Drawer and Instrument Panel partially closed, at reduced size.

When the Basic Buttons Drawer and Instrument Panel are both closed, the Wraith Scheme Main Window looks like this:

Main Window No Drawers

The Wraith Scheme Main Window, with Basic Buttons Drawer and Instrument Panel completely closed, at reduced size.



Menu Items:

MenuBar

Wraith Scheme's complete menu bar, full size.

The Wraith Scheme Menu:

Wraith Scheme Menu

The Wraith Scheme Menu, full size.

The items in the Wraith Scheme menu are pretty much Apple standards. Only three require special discussion for Wraith Scheme:

The Interpreter Menu:

The Interpreter Menu items have to do with your interactions with Wraith Scheme in the Wraith Scheme window.

Interpreter Menu

The Interpreter Menu, full size.

The Edit Menu:

Edit Menu

The Edit Menu, full size.

The Edit Menu contains only standard Apple items. There is no "undo" or "redo" for typing, because these items don't make much sense when typed input is promptly being processed by Wraith Scheme.

The Font Menu:

Font Menu

The Font Menu, full size.

The font menu allows you to increase ("Bigger") or decrease ("Smaller") the font size in the Wraith Scheme window, within limits. The smallest font available is 9 point, and the largest is 36 point. When you use these menu items, the size of all text in the Wraith Scheme window changes all at once -- they aren't "mark and click" style menu items.

The "Change Text Color..." menu item opens up a small window that allows you to change the text color Wraith Scheme uses. That small window contains a standard Macintosh "color well" that you may use to select a color. Once you have done so, use the "Preview" button to see how the color looks in the Wraith Scheme window. When you have a color you like, use the "Done" button to make the small window close. Alternatively, use the "Cancel" button to leave the background color the way it was when the small window first opened.

Change Text Color Window

The Change Text Color Window, full size.

When you use the "Change Text Color..." menu item to pick a new text color, and press the "Done" button, Wraith Scheme will ask if you want to make the new color a preference, so that it will automatically be used the next time Wraith Scheme starts up. If you reply "Yes", Wraith Scheme will put the new color into the "Preferences" window on your behalf.

The "Change Background Color..." menu item opens up a small window that allows you to change the background color of areas where Wraith Scheme displays text. That small window contains a standard Macintosh "color well" that you may use to select a color. Once you have done so, use the "Preview" button to see how the color looks in the Wraith Scheme window. When you have a color you like, use the "Done" button to make the small window close. Alternatively, use the "Cancel" button to leave the background color the way it was when the small window first opened.

Change Background Color Window

The Change Background Color Window, full size.

When you use the "Change Background Color..." menu item to pick a new background color, and press the "Done" button, Wraith Scheme will ask if you want to make the new color a preference, so that it will automatically be used the next time Wraith Scheme starts up. If you reply "Yes", Wraith Scheme will put the new color into the "Preferences" window on your behalf.

The Window Menu:

Window Menu

The Window Menu, full size.

Many of the contents of the Window Menu are standard Apple menu items. but four are not:

The Help Menu:

Help Menu

The Help Menu, full size.

The Help Menu provides access to some rather lengthy HTML files that tell how to use Wraith Scheme.

If for some reason you would like to access these files by some means other than using the menu items, there's a way. The files themselves are buried deep within the Wraith Scheme application. To find them:

Another View of Interacting with Wraith Scheme:

There is another way to think about how you may interact with Wraith Scheme:

There are five ways for Wraith Scheme to provide information to you:

There are four ways for you to provide information to Wraith Scheme:

Error Handling:

When Wraith Scheme encounters an error from which it can recover, its general strategy is to print an error message -- I hope a useful one -- in the Main Display Panel, then abort whatever Scheme processing is going on and return control to you at "top level" in the Wraith Scheme window. For example, suppose you tried to divide by zero. You might type (with a final "return")

whereupon Wraith Scheme would print

A similar error message, and a similar return to the "top level" of control of Wraith Scheme, would occur even if the attempt to divide by zero occurred deep in some elaborate Scheme procedure.

Wraith Scheme may also encounter errors from which no recovery is possible, in which case its general strategy is to open a special panel with an error message and then exit. If you should ever see a fatal error message whose cause is not obviously due to some system limitation (such as not having enough memory), I would like to hear about it: Send bug reports to Jay_Reynolds_Freeman@mac.com.

Controlling Wraith Scheme:

Differences from R5 Scheme:

Herein I describe how Wraith Scheme differs from "R5" Scheme by going through the Revised5 Report on the Algorithmic Language Scheme, section by section, and listing differences between Wraith Scheme and that standard. It is my intention that any essential or non-essential feature of Scheme, as described in the R5 report, is either provided as described, or mentioned here with an indication of how Wraith Scheme differs from the R5 report.

One major difference is that Wraith Scheme provides numerous enhancements and special features, in great part in the form of extra built-in procedures and constants whose identifiers generally begin with "e::" or "c::". I mention some of these features in passing in this section, keeping the descriptions brief for clarity of presentation. I have described them in more detail in a separate Enhancements section.

I have summarized the R5 features that Wraith Scheme lacks, in the Optional Features Omitted section. Each missing feature is also mentioned separately in the discussion of the appropriate section of the R5 report, below.

R5 Section 1:

R5 Section 2:

R5 Section 3:

R5 Section 4:

R5 Section 5:

R5 Section 6:

R5 Section 7:

Optional Features Omitted:

In the section-by-section discussions above, of how Wraith Scheme differs from the R5 standard, I have listed the optional R5 features that Wraith Scheme lacks. These features are "optional" in that the R5 report mentions them, perhaps with such language as "some implementations support ...". Here they are once again, all in one place, in summary:

Enhancements:

This section describes Wraith Scheme's non-standard features, procedures and syntax. Many are rather conventional: Most implementations of Scheme will have them in some form, but they are sufficiently dependent on the particular computer and operating system in use that the R5 report cannot specify them. Others deal with matters of controversy in the Scheme community. Possibly some version of them will be incorporated into the standard at a future date. Meanwhile, I have provided what seems best to me.

There are a moderate number of enhancements that are specific to the look and feel of the Apple Macintosh, or that allow you to access special features of the Macintosh itself. And finally, there are some enhancements that allow you to inspect or modify parts of Wraith Scheme at a rather low level. Some of these may be useful in debugging programs, or in satisfying your curiosity about what's going on. Others are there because I needed them for some purpose related to developing Wraith Scheme.

Some of these enhancements are identified by naming conventions. In particular, Wraith Scheme uses symbols which begin with the characters "e::" for enhancements that in my opinion will probably be of broad interest to users, and "c::" for more specialized enhancements that will probably be less generally useful.

By and large, enhancements whose names begin with "e::" will be reasonably well-documented and will have reasonable handling of errors. They should be no risker to use -- with "risk" in the sense of unexpected crashes and mysterious behaviors -- than standard Scheme procedures, special forms, and macros. Furthermore, these enhancements are more likely to continue to exist in the same form in future releases of Wraith Scheme, or at the very least, I will make a big to-do in documentation if there are changes.

Enhancements whose names begin with "c::" will be less-well documented, riskier, and more likely to change in future releases. Most of the "c::" enhancements are provided for my own use in developing Wraith Scheme, or are auxiliaries used by standard Scheme procedures or by "e::" enhancements. I have left them in the release and documented some of them.

You might remember the distinction this way:

e:: for enhancement, c:: for caution

A cynic might have said:

e:: for enhancement, c:: for catastrophe

Compiler:

Wraith Scheme contains a simple compiler: What it produces is not native code for the Macintosh microprocessor, but merely a somewhat more optimized form of Scheme, which the interpreter can evaluate more quickly.

    Technical Note: The compiled code is of a form that is sometimes called "threaded", with the word used in the sense of "threaded interpreted languages" -- like Forth -- rather than in the sense of "process threads".

Wraith Scheme has an internal "compile defines" flag that causes each "define" automatically to compile the quantity being defined, provided that "define" is used with the syntax

    (define (<name> <argument> ...) ... )
    

that is, with parentheses around the function name and argument list.

That flag is turned on and off by checking and unchecking the "compile defines" item of the interpreter menu, or by using the procedures described in the Enhancements section under State Flags. With the flag on,

    (define (inc x) (+ x 1))
    

will create a compiled procedure called "inc", that adds one to its argument.

The idea of compilation is to do as much of the work of a program as possible just once, at compile-time, instead of many times, every time the program is run. Thus the compiler ...

  • Expands macros,
  • Precalculates the positions within the environment of variables (including the arguments) referenced by compiled procedures,

  • Inserts the actual values of variables that are "permanent", within the bodies of compiled procedures.

Code that has had these things done runs much faster than code that has not.

Even if the "compile defines" menu item is not checked, the compiler will expand macros in procedures that are "define"d using the syntax

    (define (<name> <argument ...>) ... )
    

If the "compile defines" menu item is not checked, there is still a way to compile things, using the procedure "e::compile-form":

    (e::compile-form <form>)
    

in which <form> evaluates to what you want to compile. "<Form>" will typically be either a lambda expression or a symbol to which a lambda expression is bound. You will probably wish to bind the value returned by "e::compile-form" to a symbol, for subsequent use. For example, you might first enter

    (define inc (lambda ( x) (+ x 1)))
    

followed by

    (define inc (e::compile-form inc))
    

The result would be a compiled procedure called "inc", that adds one to its argument.

The compiler attempts to do something sensible with every <form>, but compilation has no effect on <form>s which do not evaluate to lambda expressions: Thus for example

    (e::compile-form '(1 2 3)) ;; ==> (1 2 3).
    

If you define a lambda expression with "compile defines" flag off, then turn it on, you can compile the expression easily, as shown here:

With "compile defines" off:

    (define foo (lambda ...)).
    

Then, after turning "compile defines" on:

    (define foo (e::compile-form foo))
    

The compiler includes some other procedures of interest:

    (e::define-no-compile <symbol> <form>)
    (e::define-no-compile (<symbol> ... ) <form> ... )
    

"e::define-no-compile" acts as "define" does when the "compile defines" flag is unchecked: That is, even if "compile defines" is checked, and even if quantity being defined evaluates to a lambda expression, nevertheless "e::define-no-compile" will merely bind the evaluated quantity to the <symbol>, without compiling it. Use "e::define-no-compile" to make sure something never gets compiled.

"e::define-no-compile" recursively searches its second argument for macro "calls", and expands any that it finds, before binding the result to the <symbol>.

Compiling and Permanence:

Effective use of the compiler requires understanding how it uses the "permanence" mechanism. To make a symbol permanent is to make a promise to the compiler, that whatever value is associated with the symbol at compile-time will continue to be associated with it at run-time. Thus the compiler can substitute the value for the symbol once and for all in compiled code, and save the time required to look up the symbol time after time, at run-time. The down side of permanence is that if you ever decide to make a permanent symbol un-permanent, and change its value, you will have to recompile all the procedures that use it, that were compiled while it had the first permanent value. Otherwise, those procedures will continue to use the old value.

The typical symbols you will probably wish to make permanent are the names of procedures, and there is a special procedure to help a bunch of compiled, permanent procedures all know that they are all permanent. That function is "e::substitute-new-permanent-symbols"; you use it on a procedure that has already been compiled, to let that procedure know about symbols that it contains, that have been made permanent after it was compiled:

    (e::substitute-new-permanent-symbols <form>)
    

Note that you do not have to bind the result of "e::substitute-new-permanent-symbols" to anything; that procedure modifies its argument: It looks through the function body for symbols that have become permanent, and substitutes in their values.

Here is some boiler-plate for how to use the "permanence" mechanism effectively in compiled code. Suppose that the "compile defines" menu item is checked, and that you wish to compile three functions, "foo", "bar" and "baz", that call each other, or that call themselves recursively, or both. The idea is to define them all first, then make them all permanent, then apply "e::substitute-new-permanent-symbols" to all of them. You do all this with the "compile defines" flag set:

    (define my-function-names '(foo bar baz)
    
    (define (foo ...) ...)
    (define (bar ...) ...)
    (define (baz ...) ...)
    
    (map e::set-permanent! my-function-names)
    (map e::substitute-new-permanent-symbols my-function-names)
    

Debugger:

The debugging mechanism provided with Wraith Scheme is very incomplete, though there is a hook for making it better. Wraith Scheme's mechanism for handling recoverable errors -- the kind that eventually return control to top level --knows to look for a symbol called "e::debug". If that symbol is bound to a procedure, the error-handling message will call it with a single argument. Thus you may create a debugger merely by defining "e::debug", like this:

    (define e::debug (lambda (x) ...))
    
Wraith Scheme will then call "e::debug" as part of its error handling, after the error message has been printed, instead of returning control to the top-level environment.

The argument to "e::debug" will be a non-empty list of all the environments in the lexical scope of the place where the error happened. The last member of that list will be the top-level environment: It will be a vector, each of whose elements is a list of symbols. Every symbol bound in the top-level environment will appear in exactly one vector element. If the list that is passed to "e::debug" has more members, its first member will be a list of the symbols bound in the lexical scope most local to the error, its second will be a list of the symbols bound in the next lexical scope outward, and so on till the top level. Only the last member will be a vector; all the others will be lists.

You may have your "e::debug" do whatever you like with this information. You might display the symbols. It will be hard to obtain their values, because the environment list passed to "e::debug" as an argument is not the one Wraith Scheme searches automatically from within "e::debug", when looking for variable bindings. What's more, the environment list is not a very interesting data structure for debugging. Much more useful would be access to Wraith Scheme's run-time stack (which is different from the central processor's "machine stack"). You can always show the contents of this stack, whether from the debugger or not, by calling the procedure "e::show-stack", but there is presently no reasonable way to learn what procedures are associated with specific items on the stack, or to investigate any particular stacked item in more detail.

Your "e::debug" probably ought to terminate with a call to "e::reset", so that Wraith Scheme will return to top-level for further input after "e::debug" has run.

Be careful that "e::debug" is correct code. It is difficult to recover from errors in the debugger. Recursive errors are particularly nasty: The handling of an error in the debugger invokes another copy of the faulty debugger, which causes another error, and so on.

In addition to whatever the debugger may do, Wraith Scheme handles non-fatal errors simply: It prints out some information about the error and what caused it, before invoking any debugger that may be present. If no debugger is present, Wraith Scheme then returns control to the top-level loop. Different things might happen when a debugger is loaded -- depending on what the debugger is supposed to do.

The printed information will include the name of the last lambda expression entered before the error was encountered, whether or not that lambda expression had returned. It will also include the names of all lambda expressions whose activation records are stacked in Wraith Scheme's internal stack; however, this list will not include the names of lambda expressions that were departed from by a tail-recursive call: Their activation records will by then no longer be stacked.

If you are wondering what I mean by the "name" of a lambda expression, wait for a few paragraphs.

By the way, fatal errors are handled differently, depending on what they are and when they occur: Usually, Wraith Scheme will print out some kind of message and then exit. Any debugger present will not be called.

    Technical Note: A fatal error is one so serious that Wraith Scheme can no longer run, and since any debugger of the kind described necessarily runs in Wraith Scheme, it cannot run, either.

If the you ever see an with a message like

    "Implementation error ..."
    

or

    "Implementation: ..."
    

then I would very much appreciate a bug report with as many details as you can provide. (In particular, include the entire message.) Such messages indicate that I have inadequately guarded against some particular problem: It's my fault; I will be eager to do better.

  • Lambda Expression "Names":

    The internal representation of a Wraith Scheme lambda expression has a place where Wraith Scheme can record an identifier, which I will somewhat incorrectly refer to as the lambda expression's name. This information can be of great use in a stack trace, for error reporting or debugging. That isn't quite as simple as storing the identifier to which the lambda expression is bound, because a lambda expression may be bound to more than one identifier, as in

      (define (dessert-topping) (lambda () ...)
        ;; It's a dessert topping!
      (define floor-wax dessert-topping)
        ;; No!  It's a floor wax!
      

    Or a lambda may have no name at all, as in

      ((lambda (n) (+ n 1)) 3)
      

    What Wraith Scheme does is initialize each lambda expression's "internal" name to (). If a lambda is subsequently bound or assigned to a symbol, Wraith Scheme records that symbol within the lambda expression, as its name. Thereafter, if that lambda expression should subsequently be rebound or reassigned by "define", by "set!", by "e::define-no-compile", or by being bound to one of the top-level loop variables, Wraith Scheme overwrites the old internal name with the new one. Those are the only ways to cause a name to be overwritten: Wraith Scheme will not give a new internal name to a lambda which already has one, when that lambda is rebound or reassigned by any other means.

    Thus a lambda expression which has been named at top-level will not be renamed if it gets passed to a procedure as a parameter, or if it gets rebound locally by "let" or some similar mechanism. On the other hand, lambda expressions which do not have top-level names will be named at first opportunity, even if only by being bound to a local variable or to a formal parameter.

    You might say that lambda expressions want names so badly that they will grab one at the first opportunity, and will give it up only when forced to do so.

    I hope these conventions will correspond reasonably to your notions of what a lambda expression ought to think its name is, and that they will help with debugging in any case.

    In case it is not yet clear, this business of storing a lambda expression's name inside the lambda expression is an addition to, not a substitute for or alteration of, the normal Scheme operations of binding and assignment: It is merely a debugging aid. If you didn't know about the "internal" names (and if you never made any mistakes that caused a stack trace to be printed), you'd never notice they were there. What's more, you don't need to know about them to use Wraith Scheme.

    The fact that the "name" of a lambda expression may be one of the top-level loop variables can be quite confusing if you do not know to expect it. Consider the following lines from the Wraith Scheme interpreter, which I have numbered for convenience:

       1    (define (foo x) (+ x 3))
       2    foo
       3    (display foo)
       4    #<Interpreted lambda expression, possibly named "foo">#t
       5    foo
       6    #<Interpreted lambda expression, possibly named ">*<">
       7    foo
       8    #<Interpreted lambda expression, possibly named ">*<">
       9    foo
      10    #<Interpreted lambda expression, possibly named ">*<">
      11    3
      12    3
      13    (display foo)
      14    #<Interpreted lambda expression, possibly named ">**<">#t
      

    Lines one through four are pretty normal -- you define a procedure and find that its "name" is "foo" -- at least, for the moment. But typing "foo" in line five causes the value of foo -- the lambda expression -- to be bound to ">*<", so that symbol shows up as foo's name in line six. Lines seven through ten repeat the process, but when you type "3" in line 11, "3" is the next item bound to ">*<", and "foo" next surfaces as the value of ">**<", and so it goes.

    You probably don't usually type the names of procedures at top-level, but if you had, then seeing a symbol like ">*<" pop up in a debugging trace would prompt you to scroll back and see what you had been doing at top-level. So I left this feature the way it is, possible confusion notwithstanding.

    Once again, this business of storing a lambda expression's name inside the lambda expression is an addition to, not a substitute for or alteration of, the normal Scheme operations of binding and assignment: It is merely a debugging aid.

Logic Programming:

Wraith Scheme provides some support for logic programming in Scheme along the lines of Friedman, Byrd and Kiselyov, 2005). Wraith Scheme does not include any of the fancy software from this work; that's copyrighted, but I hope there are enough primitives to get you going.

  • Wraith Scheme provides two specialized "logic constants", "#u" and "#s", for use in logic programming. You couldn't even get Wraith Scheme to read these identifiers unless I built them in, because R5 identifiers are not generally allowed to start with '#'. So here they are, for anyone who wishes to use them.

    Each of "#u" and "#s" evaluates to itself.

  • Procedures for Logic Programming:

    (e::logic-constant? <object>)
    

      Returns #t if, and only if, its argument is either #u or #s; otherwise, returns #f.

Procedures and Forms:

This subsection describes some of the procedures and special forms that are present in Wraith Scheme, that are not part of the R5 standard. I have by no means described all such extras: If you explore the system with the various low-level inspection tools described herein, you will find many procedures I do not mention. I am not trying to keep secrets: Rather, I have described only those enhancements that seem stable enough to use in your own code. The ones not described may change in detail or disappear entirely in future releases of Wraith Scheme.

All the global symbols that I have used in constructing these enhancements start with either "e::" ('e' for enhancement) or with "c::" ('c' for compiler). To avoid naming conflicts with present and future enhancements, please do not create global symbols that start with either of these trios of characters.

    Technical Note: The double-colon in "e::" and "c::" may suggest some kind of "package" system, such as is widely used in other Lisps. There is no package system in Wraith Scheme. The colon is an ordinary character. Symbols that contain a double colon are in no way different from symbols that do not. I use the double-colon in this way merely as a naming convention.

And please be wary about using any "c::..." procedures in your own code. Some will cause a crash -- Wraith Scheme will cease to operate -- if misused.

  • Bit Operations:

    There are several procedures which allow direct manipulation of the individual bits of a 32-bit fixnum. Each requires integer arguments whose values can be coerced to 32-bit fixnums.

    (e::bit-and <integer> <integer>)
    

      Coerces its arguments to 32-bit fixnums and returns their bit-by-bit Boolean "and".

    (e::bit-not <integer>)
    

      Coerces its argument to a 32-bit fixnum and returns its bit-by-bit Boolean "not".

    (e::bit-or <integer> <integer>)
    

      Coerces its arguments to 32-bit fixnums and returns their bit-by-bit Boolean "or".

    (e::bit-xor <integer> <integer>)
    

      Coerces its arguments to 32-bit fixnums and returns their bit-by-bit Boolean exclusive "or".

    (e::bit-shift-left <integer> <integer>)
    

      Coerces its arguments to 32-bit fixnums. Returns the first argument shifted left by the number of bits which is the second argument, inserting zeros at the right as necessary.

    (e::bit-shift-right-arithmetic <integer> <integer>)
    

      Coerces its arguments to 32-bit fixnums. Returns the first argument shifted right by the number of bits which is the second argument, replicating the most-significant bit at the left as necessary.

    (e::bit-shift-right-logical <integer> <integer>)
    

      Coerces its arguments to 32-bit fixnums. Returns the first argument shifted right by the number of bits which is the second argument, inserting zeros at the left as necessary.

  • Evaluation:

    (e::cons-with-continuation <object>)
    

      This procedure is left over from older releases of Wraith Scheme, that did not implement the "R5" Scheme standard. That standard has an "eval" procedure, which Wraith Scheme now supports. Yet "e::cons-with-continuation" is still there, in case anyone wants to use it.

      Many Lisps would call this procedure "eval". It causes its argument to be evaluated in the same environment as that in which "e::cons-with-continuation" itself was called.

        Technical Note: In case the name does not convince you that "e::cons-with-continuation" simply conses its unevaluated argument onto the next-to-be-evaluated end of the current continuation, that is indeed what it does.

      Thus:

        (e::cons-with-continuation '(+ 2 2))    ;; ==> 4
        (define b 3)                            ;; ==> 3
        (define a 'b)                           ;; ==> a
        (e::cons-with-continuation a)           ;; ==> 3
        

      The main use of "eval" and similar features is a bit more complicated, however: One typically builds up the argument to be passed to eval a piece at a time, often in quite distinct and changing environments, then evals it all at once:

        (define to-be-evaled '())
        (set! to-be-evaled (cons 'operator to-be-evaled))
        (define x 42)
        (define y 88)
        (set-cdr! to-be-evaled (list 'x 'y))
        (define x 2)
        (define y 2)
        (define operator +)
        to-be-evaled                              ;; ==> (operator x y)
        (e::cons-with-continuation to-be-evaled)  ;; ==> 4
        

      In contrast, suppose we had slightly changed the line containing "set-cdr!" ...

        (define to-be-evaled '())
        (set! to-be-evaled (cons 'operator to-be-evaled))
        (define x 42)
        (define y 88)
        (set-cdr! to-be-evaled (list x y))        ;; NOTE: No quotes.
        (define x 2)
        (define y 2)
        (define operator +)
        to-be-evaled                              ;; ==> (operator 42 88)
        (e::cons-with-continuation to-be-evaled)  ;; ==> 130
        

      Here is another example: In it, note that even though "to-be-evaled" is defined in an environment in which x, y, and z are all zero, what happens when "to-be-evaled" is consed with the continuation depends on what x, y, and z were in the environment where that happened.

        (define x 0)
        (define y 0)
        (define z 0)
        
        ;; At this point x, y and z are all zero.
        
        (define to-be-evaled '(list x y z))
        
        (let ((y 1)(z 1))            ;; Now y and z are one.
          (let ((z 2))               ;; Now z is two.
            (e::cons-with-continuation to-be-evaled)))
        
        ;; ==> (0 1 2)
        

    There has been controversy in the Scheme community concerning what "eval" ought to do, and whether it even ought to be part of the Scheme language at all.

  • Files and Directories:

    (e::current-directory)
    

      Returns a string that is the full pathname of the "current directory", which is where Wraith Scheme operations look for files when you do not provide a complete pathname. The last character in the string returned will be a '/'.

    (e::error-port)
    

      Returns the port to which Wraith Scheme sends error messages. That is usually the console, even when Wraith Scheme is using a file for other output.

      This procedure allows you to write your own error handlers that send messages to the same port that Wraith Scheme uses.

    (e::file-exists? <string naming a file>)
    

      Returns #t or #f according to whether or not the pathname (full or partial) given by the string names a file that can be opened for reading by the Unix "fopen" command.

      The name of this procedure is slightly misleading, in that it is possible that the named file may exist but not have appropriate Unix permission settings for reading by the current user of Wraith Scheme. In that case, the procedure will return #f.

      There is no way to tell whether a returned value of #f means that the file does not exist, or that some directory along the path does not exist, or that there is some other problem: The procedure returns #f if for any reason it cannot find the indicated file, or cannot open it for reading.

      This procedure closes any file that it opens.

     (e::program-directory) 

      Returns the path to the directory containing the Wraith Scheme application itself; that is, a Unix path that starts with "/" and ends just before the name "Wraith Scheme.app". The last character in the string returned will be a '/'.

    (e::set-current-directory! <string naming directory>)
    (e::set-current-directory!)  ;; With no argument, uses a dialog.
    

      Changes the "current directory" to the directory whose pathname (full or partial) is given by the string. Appends a '/' to the pathname, if the pathname does not already end in a '/'. Returns the pathname, as a string. Reports an error when the string is not a valid pathname (full or partial) to a directory. The "current directory" is where Wraith Scheme operations look for files when you do not provide a complete pathname.

    (e::startup-directory)
    

      Returns a string that is the full pathname of the "startup directory"; that is, of the directory that was the "current directory" when you started Wraith Scheme. The last character in the string returned will be a '/'.

  • Infinities and Nans:

    (e::nan? <object>)
    

      Returns #t if the <object> is an IEEE "nan" (which stands for "not a number"), otherwise returns #f.

    (e::inf? <object>)
    

      Returns #t if the <object> is an IEEE infinity (a special bit pattern used when floating-point operations have calculated numbers too large to be represented as ordinary IEEE floating-point numbers), otherwise returns #f.

  • Inspecting Scheme Objects:

    (e::inspect <object>)
    

      Displays some useful information about the <object> and returns the <object>. Just what is displayed depends on what the <object> is. The fact that "e::inspect" returns its argument means that you can generally wrap a call to "e::inspect" around any expression in a Scheme program, to see what is going on, without otherwise interfering with the operation of the program.

    (e::inspect-world <string naming a file>)
    (e::inspect-world)
    

      Assumes that the string is a path to a Wraith Scheme world file, and on that basis, attempts to open the world file and examine its contents, without actually making the file become the world in use by Wraith Scheme. Reports an error if there is insufficient memory to load the file, and may cause Wraith Scheme to fail and quit if the file is not actually a Wraith Scheme world.

      If no file name is given, puts up a standard dialog box for selecting a file to inspect.

  • Macros -- An Alternate Implementation:

    In addition to the "hygienic" macro implementation described in the R5 report, Wraith Scheme provides a "lower-level" macro implementation, that is more like the macro implementations in older forms of Lisp.

      Technical Note: This older implementation of macros descends from Wraith Scheme's predecessor, Pixie Scheme, which I wrote before the R5 report was released. The older form is "non-hygienic", but is in some ways more versatile than what the R5 report describes, so I left it in as an enhancement.

      Besides, several key elements of Wraith Scheme are written as Scheme macros using the older macro implementation.

    (e::expand-macro <macro>)
    

      Expands a macro. Details follow in an example, a few paragraphs down.

    (e::macro? <object>)
    

      Returns #t if <object> is a macro, and returns #f if not.

    (e::macro <symbol> <expression>)
    

      Binds a macro to <symbol>. Other Lisp implementations might have used the name "defmacro" for this operation.

    (e::macro-body <expression>)
    

      Creates a macro from the <expression>, but does not bind it to a symbol. That is,

        (e::macro <symbol> <expression>)
        

      is equivalent to

        (define <symbol> (e::macro-body <expression>)
        

    Wraith Scheme implements this older form of macros in a rather conventional way. I will first describe this facility simply, glossing over some technical points, and will then fill in the details.

    To begin, "e::macro" resembles "define": The action of

      (e::macro <symbol> <expression>)
      

    is to evaluate the <expression>, to declare that whatever the evaluation returns is a macro, and finally to bind that macro to the <symbol>.

    The action of "e::macro-body" more nearly resembles the evaluation of a lambda expression: That is, the action of

      (e::macro-body <expression>)
      

    is merely to evaluate the <expression> and declare that whatever the evaluation returns is a macro.

    There is one catch: The final action of the <expression> must be to evaluate a lambda expression of one argument, so that the procedure thereby created is the value that will become the macro. Wraith Scheme reports an error if the value of the <expression> is not a procedure that was derived from a lambda expression of one argument.

    A macro is invoked, or "called", by evaluating a pair whose car evaluates to a macro. That is, if you have defined

      (e::macro my-macro ...)
      

    then you may invoke my-macro as

      (my-macro <stuff>)
      

    The action of such a call is (1) to pass the entire pair -- in this case "(my-macro <stuff>)" -- to the procedure associated with the macro; whereupon (2) that procedure does whatever it is supposed to do, to the pair; and (3) the result returned by the procedure is itself evaluated.

    Here is a simple example. Suppose you are tired of writing assignment statements in the form "(set! foo bar)", and would rather write them as "(assign bar to foo)" Define the macro:

      (e::macro assign (lambda (form) `(set! ,(cadddr form) ,(cadr form))))
      

    You can then write

      (define foo #f)      ;; ==> foo
      (define bar 3)       ;; ==> bar
      (assign bar to foo)  ;; ==> foo
      

    The last expression assigns bar, which evaluates to 3, to foo. Now

      foo                  ;; ==> 3
      

    Let's look closely at how that works. The macro call "(assign 3 to foo)", causes the entire expression, "(assign 3 to foo)" to be passed as the argument "form" to "(lambda (form) `(set! ,(cadddr form) ,(cadr form))))". That procedure returns a list whose first element is "set!", whose second element is the cadddr of the form (namely the symbol "foo"), and whose third element is the cadr of the form, namely the number 3. That list, "(set! foo 3)" is in turn evaluated, causing 3 to become the value of foo.

    You can see what is happening by evaluating

      (e::expand-macro '(assign 3 to foo)) ;; ==> (set! foo 3)
      

    This expression causes only the first two parts of the macro call "(assign 3 to foo)" to take place: It returns the unevaluated result from the procedure, namely the list "(set! foo 3)".

    If you want to see the lambda expression itself, instead of what happens when you apply it, use "e::inspect". When you enter

      (e::inspect assign)
      

    Wraith Scheme prints some information about where in Scheme memory the macro is located, then prints the lambda expression itself, though not as nicely pretty-printed as I have provided it here.

      (lambda (form)
        (quasiquote (set! (unquote (cadddr form))
                          (unquote (cadr form)))))
      

    Note in passing that "assign" is not a very well-behaved macro. For simplicity, it does not include various tests for syntax errors. A better version would have a lambda expression that checked that "form" was a list of exactly four elements, that the third element was the symbol "to", and that the fourth element was a symbol.

    The matter I have glossed over is what environments the various evaluations take place in. (Many people find the subject of environments confusing: You need not worry too much about this matter at first, though it may come back to haunt you if you become a serious Scheme enthusiast.)

    Briefly, the expansion of a macro -- that is, the evaluation of the procedure of one argument that is assigned to the macro name -- takes place in the lexical scope of the macro definition; but the second evaluation, of whatever expression the expansion returns, takes place in the lexical scope of the macro call.

    Here is an example that may make this issue clearer. Maybe ...

    First, let's define a global variable, named "my-variable", whose value is the symbol "global-value".

      (define my-variable 'global-value) ;; ==> my-variable
      my-variable                        ;; ==> global-value
      

    Now let's create a macro named "foo", whose body contains several instances of the symbol "my-variable".

      (e::macro foo
        (display "Defining foo -- my-variable is ")
        (display my-variable)
        (newline)
        (lambda ( the-argument-is-not-used )
          (display "Expanding foo -- my-variable was ")
          (display my-variable)
          (display " in the environment where foo was defined.")
          (newline)
          (display "In the present environment my-variable is ")
          'my-variable))
      

    As "foo" is being defined, the first two "display"s and the subsequent "newline" are evaluated, so that what appears in the Wraith Scheme window is

      Defining foo - my-variable is global-value
      foo
      

    The "display"s printed the value of "my-variable" in the environment where foo was defined; that value was still "global-value". The lambda expression was then converted into a procedure, which became the value of "foo", which was returned and displayed at top level. The procedure uses "my-variable" in the fifth-from-last line of its definition, in "display". The value of "my-variable" so referenced is again from the environment in which "foo" was defined. So when "foo" is called, it will print

      Expanding foo -- my-variable is global-value
      

    before the lambda expression returns any value.

    The value returned by the lambda expression is a quoted symbol, "'my-variable", and that leading quote is a key to understanding what happens next. This expression will be evaluated in the environment in which the call to "foo" took place. In that environment, "my-variable" will not necessarily have the same value that it did in the environment where "foo" was defined. Thus after the return value has itself been evaluated, it will become

      (my-variable is <?>)
      

    We don't now know for sure what the "<?>" will be.

    To continue the example, let's create a local environment in which "my-variable" has as value the symbol "local-value", and call "foo" in that environment. We might evaluate

      (let ((my-variable 'local-value)) (foo))
      

    What gets printed is, after reformatting it to make the lines shorter:

      Expanding foo -- my-variable was global-value
        in the environment where foo was defined.
      In the present environment my-variable is local-value
      

  • Miscellaneous Predicates:

    (e::closed-port? <object>)
    

      Returns #t if <object> is an input port or an output port which has been closed, and returns #f otherwise.

    (e::fixnum? <object>)
    

      Returns #t if the <object> is a number stored as a 32-bit twos-complement integer, otherwise returns #f. All numbers so stored are integers.

    (e::float? <object>)
    

      Returns #t if the <object> is stored in an IEEE floating-point format, otherwise returns #f.

      These formats can represent integers, rationals which are not integers, IEEE nans and IEEE infinities. Wraith Scheme finds occasion to use IEEE formats for all of these entities.

    (e::forced? <object>)
    

      Returns #t if <object> is a promise which has been forced, and returns #f otherwise.

    (e::long-float? <object>)
    

      Returns #t if the <object> is stored in IEEE 64-bit floating-point format, otherwise returns #f.

    (e::promise? <object>)
    

      Returns #t if <object> is a promise, and returns #f otherwise.

    (e::short-float? <object>)
    

      Returns #t if the <object> is stored in IEEE 32-bit floating-point format, otherwise returns #f.

  • Miscellaneous Procedures:

    (e::deep-copy <object>)
    

      Constructs a copy of its argument which is "equal?" to the argument, but in which copied vectors, lists and strings in corresponding positions in the structure are not themselves "eq?" to one another.

    (e::error <string>)
    

      Prints a string to the default error port, and resets Wraith Scheme to the top-level loop.

    (e::gensym)
    

      Returns a symbol guaranteed to be different from any symbol already encountered by Wraith Scheme. Symbols created by "e::gensym" print as strings of the form "gXXXXX...", where "XXXXX..." are the digits of a positive decimal integer that is greater than or equal to 23000.

        Technical Note: The choice of "23000" is in memory of Ratfor. "Ratfor" is not the name of one of my cats; at least, not yet.

    (e::original-cwcc <object>)
    

      Wraith Scheme implements "dynamic-wind" generally along the lines of the implementation demonstrated by Jonathan Rees (1992) in "The Scheme of Things: The June Meeting", published in Lisp Pointers V(4), October-December 1992. That implementation involves modifying "call-with-current-continuation". The unmodified version of "call-with-current-continuation" is available as "e::original-cwcc".

    (e::system <string>)
    

      Passes the given string to the Unix "system" function, for execution, and returns whatever "system" did; that is, an integer having to do with whether the execution was successful. (See the Unix documentation for "system".) For example,

        (e::system "cal > ~/calendar.out")
        

      puts a calendar for the present month in a file called "calendar.out" in your home folder.

      This procedure is very powerful; it is a doorway into the capability of the the entire Unix system. Unfortunately, there is no easy way to obtain the details of what happened, other than recording them to a file (as in the example just given) for subsequent examination.

        Technical Note: Actually, that isn't quite true. Any terminal output from the Unix "system" command ends up in the Macintosh console log file. (See the "Console" application, in the "Utilities" folder, in the "Applications" folder.) If all you need to do is look at the results, that might be enough; but if you want Wraith Scheme to process the results and do something with them, you will have to redirect them to a file, as in the example just given, and have Wraith Scheme read them in from there.

    (e::time)
    

      Accesses the Unix "time" function, which returns an integer that is the number of seconds since the start of 1970.

    (e::usleep <integer>)
    

      Calls the Unix "usleep" function with the given integer as argument. Nominally, this function makes the Wraith Scheme interpreter sleep -- ignore input and do nothing -- for a number of microseconds which is equal to the given integer. Because of delays in starting up the procedure, the granularity of the period of sleep is much coarser than one microsecond; the calling interface merely provides consistency with the Unix function.

      Only the part of Wraith Scheme that reads, evaluates, and prints Scheme expressions is put to sleep by this command. Wraith Scheme will respond to many user actions while sleeping; for example, changes in window size. Actions that would cause the processing of Scheme expressions will not take place until Wraith Scheme has waked up, and may block other user actions until wake-up has taken place.

      In principle, calling "e::usleep" with a sufficiently large argument could cause Wraith Scheme to sleep for more than an hour. Users of this command might well learn how to force Wraith Scheme to quit by asking the Macintosh Finder to assist: Hold the "ctrl" key down while clicking on the Wraith Scheme icon in the Dock.

    (e::version)
    

      Returns a string that shows the date and time of creation of the version of the Wraith Scheme program that is running.

  • Multiple-Values Objects and Operations:

    Wraith Scheme implements the procedures "values" and "call-with-values", as described in the "R5" report. The implementation features an additional kind of Scheme object, which I have unimaginatively labeled a "multiple values return". The intended use of these objects is to pass data between "values" and "call-with-values", but if you should happen to call "values" in some context other than providing input to "call-with-values", you might encounter one. Thus, for example, at top level:

      (values 2 3 4)  ;;  ==>
      
      #<Multiple Values Return>
      List of values: (2 3 4)
      

    Furthermore:

    (e::multiple-values? <object>)
    

      Returns #t if the <object> is a multiple-values return, otherwise returns #f.

  • Numeric Formatting:

    Straight R5 Scheme provides no convenient way to format numbers in varying ways without writing a lot of code on your own. Wraith Scheme has a few enhancements to do some of the common formatting tasks, and perhaps to make it easier to create your own code to do more such tasks.

    The interface is built on a single low-level procedure, which uses the numeric formatting capabilities of the underlying C++ implementation in which Wraith Scheme is written. (I do not propose to tell you how to do numeric formatting in C in this document, since there are plenty of widely available sources that do a better job of that than I could. For example, try typing "man printf" in a Unix shell such as the Macintosh "Terminal" application.)

    The low-level procedure is:

    (c::number->string-with-c-format <number> <string>)
    

      This procedure accepts a number as first argument, coerces it to a C++ "double", and converts it to a number using the second argument as a C++ "format" string.

        Technical Note: The underlying C++ call ends up as

          snprintf( scratch, 256, <your number coerced to double>, <your format string>)

        in which "scratch" is a pointer to a buffer containing 256 characters. Following this C++ call, the content of "scratch" is again copied into a newly-allocated string in Wraith Scheme's main memory, so there is no need to worry about saving "scratch" or overwriting it.

      Note that "c::number->string-with-c-format" does no checking whatsoever of whether its "string" argument is appropriate for use as a C++ "format" string. Thus there is a noteworthy probability that ill-considered use of this procedure may cause Wraith Scheme to crash. This procedure is perhaps best used as a primitive for procedures which are themselves well tested and debugged.

      Thus for example:

        (c::number->string-with-c-format 1 "%.3f") ;; ==> "1.000" (c::number->string-with-c-format 29.95 "For the low, low price of only $%.2f!!") ;; ==> "For the low, low price of only $29.95!!"

    There are two additional procedures which operate at slightly higher level:

    (e::number->string-with-n-decimals <number> <number>)
    

      This procedure returns a string containing the first argument printed in decimal format with n digits to the right of the decimal point, where n is the second argument. The value of n must be in the range [0 .. 10].

      For example:

        (e::number->string-with-n-decimals 1/3 3) ;; ==> "0.333" (e::number->string-with-n-decimals (- (/ 1000 3)) 6) ;; ==> "333.333333"

    (e::money->string <number>)
    

      Prints the number with two digits to the right of the decimal point, as in:

        (e::money->string 29.95) ;; ==> "29.95"

  • Permanence:

    If only one value will ever be bound or assigned to a particular symbol, you can speed up the operation of both interpreted and compiled code by making that symbol "permanent". You can reverse the process later, if necessary; but if you do, be sure to recompile any compiled expressions that use the symbol: Otherwise, strange things may happen. It is possible -- though perhaps not useful -- to make permanent a symbol that already has different values bound to it in different scopes.

    Wraith Scheme will report an error if you attempt to bind or to assign a value to a permanent symbol.

    Most of the symbols that denote the built-in primitive operations of Wraith Scheme are permanent. These symbols include "+", "car", "if", "call-with-current-continuation" and so on.

    (e::set-permanent! <symbol>)
    

      Makes the value assigned to <symbol> be permanent; that is, declares to Wraith Scheme that the value presently assigned to <symbol> will never change. Does not change that value.

    (e::clear-permanent! <symbol>)
    

      Makes the value assigned to <symbol> be non-permanent; that is, declares to Wraith Scheme that the value presently assigned to <symbol> may change. Does not change that value.

    (e::permanent? <symbol>)
    

      Returns #t if the <symbol> is permanent, otherwise returns #f.

        Technical Note: I added the "permanent" feature because in another Lisp system, I once inadvertently and unknowingly redefined "T" -- its "true Boolean". That system kept a master value of T somewhere, to copy into code when necessary. Somehow, I changed it. Code that already had the "right" value of T continued to work correctly, but new stuff did not. The effect was that I had a weird bug, and whenever I changed a procedure, in the act of debugging, the bug spread. Unreal ...

        The folks at MIT who wrote the original "MacLisp" (a 1970's-vintage Lisp that ran on mainframe computers, not -- as you might suppose -- a Lisp for the Macintosh) issued special error messages if you tried to alter the values of T and nil in that system. They were:

          VERITAS AETERNA -- do not setq T!
          NIHIL EX NIHIL -- do not setq nil!
          

        They had the right idea. (Welcome to the twilight zone -- a CalTech graduate -- me -- just said something complimentary about MIT.)

        Perhaps you can figure out how I know about those error messages ...

        Elsewhere herein I tell how, in the early stages of development of Pixie Scheme -- Wraith Scheme's predecessor -- I accidentally managed to create nearly nine billion separate and operationally inequivalent kinds of truth and falsehood.

  • Print Length and Depth:

    Eight procedures deal with parameters that control how much of a complicated list or vector gets printed, and thereby incidentally prevent Wraith Scheme from entering an infinite loop when asked to print a circular data structure. There are four such parameters, but their values are not directly available: You must use the functions to manipulate them. One parameter limits the number of elements of a list that will be printed. If this parameter is 3, then '(1 2 3 4 5) will print as

      (1 2 3 ...)
      

    The second parameter similarly limits the number of elements of a vector that will be printed.

    The third parameter limits the depth of nested lists that will be printed. If that parameter is 3, then '(((((foo))))) will be printed as

      (((...)))
      

    The fourth parameter similarly limits the depth of nested vectors that will be printed.

    (e::list-print-depth)
    

      Returns the current maximum depth to which nested lists will be printed.

    (e::list-print-length)
    

      Returns the current maximum number of elements of a list that will be printed.

    (e::vector-print-depth)
    

      Returns the current maximum depth to which nested vectors will be printed.

    (e::vector-print-length)
    

      Returns the current maximum number of elements of a vector that will be printed.

    (e::set-list-print-depth! <positive integer>)
    

      Sets the current maximum depth to which nested lists will be printed. The <positive integer> must exceed two.

    (e::set-list-print-length! <positive integer>)
    

      Sets the current maximum number of list elements that will be printed. The <positive integer> must exceed two.

    (e::set-vector-print-depth!  <positive integer>)
    

      Sets the current maximum depth to which nested vectors will be printed. The <positive integer> must exceed two.

    (e::set-vector-print-length! <positive integer>)
    

      Sets the current maximum number of vector elements that will be printed. The <positive integer> must exceed two.

  • Random Numbers:

    Two procedures provide access to a quite good Unix random number implementation:

    (e::random)
    

      Returns a random integer generated by the Unix function "random" (which should not be confused with the earlier Unix random-number implementation, "rand").

    (e::srandom <integer>)
    

      Seeds the Unix "random" implementation with the given integer.

    Wraith Scheme itself seeds the "random" implementation with a different number every time it starts up. If you wish to generate a repeatable string of random numbers -- perhaps for debugging a program that uses "e::random", re-seed the implementation, via "e::srandom", with the same integer, before each sequence of calls to "e::random".

    See the Unix documentation for details of "random" and "srandom".

  • State Flags:

    Several procedures allow Scheme programs to examine and modify the internal flags that control whether defines are compiled automatically, and whether the display routines for numbers use the full precision available.

    (e::set-compiler-on!)
    (e::clear-compiler-on!)
    (e::compiler-on?)
    

      The preceding procedures respectively set, clear, and return the value of the internal flag that controls whether Wraith Scheme compiles define automatically. The procedures that change the flag take effect at once, but the corresponding displays in the Wraith Scheme Instrument Panel and in the Interpreter Menu may not update immediately. Be patient: They will catch up when Wraith Scheme isn't busy.

    (e::set-show-full-precision!)
    (e::clear-show-full-precision!)
    (e::show-full-precision?)
    

      The preceding procedures respectively set, clear, and return the value of the internal flag that controls whether Wraith Scheme display routines use the full precision available. The procedures that change the flag take effect at once, but the corresponding displays in the Wraith Scheme Instrument Panel and in the Interpreter Menu may not update immediately. Be patient: They will catch up when Wraith Scheme isn't busy.

  • Storage Management:

    (e::full-gc)
    

      Performs garbage collection. Wraith Scheme will also automatically invoke this routine when necessary.

        Technical Note: The garbage-collection algorithm used by Wraith Scheme compacts lists quite efficiently, using "cdr coding" wherever possible.

      The speed of garbage collection will vary from fast -- when the Wraith Scheme main memories are contained entirely within physical memory chips -- to very slow -- when the Wraith Scheme main memories are in part stored as virtual memory, on disk. It takes a long time to "swap"; that is, to move data back and forth between disk and physical memory. On a 2006 model Macbook, with a 2 GHz Intel Core Duo processor and 1 GByte of memory, with no other user processes but Wraith Scheme running, with a Wraith Scheme main memory size of nearly 1 GByte, with a substantial portion of main memory containing non-garbage, I have seen garbage collection take as long as twenty minutes.

        Technical Note: Most of the swapping takes place early in the garbage-collection process, and I have no way to monitor the progress of swapping, so there isn't much point in using a progress indicator to show what is going on; it would just sit at a fixed position for a long time, then rapidly zoom through the rest of its range.

    (e::ninety-percent-used?)
    

      Returns a boolean, which is true if the amount of storage space in use by Wraith Scheme equals or exceeds ninety percent of the total amount of storage available.

    (e::room)
    

      Returns an integer, which is the number of bytes of storage space available to Wraith but yet unused. When this number becomes too small, garbage collection must take place, as an attempt to free up some space.

    (e::show-room)
    

      Shows some information about how much storage space has been used, and about how much remains available. Returns #t.

    (e::store-size)
    

      Returns an integer, which is the total number of bytes in either one of the two storage spaces used by Wraith Scheme. This number is necessarily the sum of the number of bytes used and the number that remain available. It is also one of the numbers printed out at the top of the Wraith Scheme window when the program begins.

  • System Information:

    This section deals with procedures that allow examination or modification of some of the internal data structures used by Wraith Scheme. Abuse of some of these functions will cause fatal errors, crashes and other disasters. Detailed description of these data structures is beyond the scope of this help file; however, experienced Lisp programmers will know what I am talking about.

    (e::bound-instance? <symbol>)
    

      Returns #t if the <symbol> has a value in the environment in which "e::bound-instance?" is called, otherwise returns #f. Many Lisp systems would call this function "boundp".

    (e::get-tag <object>)
    

      Returns a positive integer that indicates the type of <object> and conveys information about how <object> is cdr-coded.

    (e::set-tag! <object> <integer>)
    

      Changes Wraith Scheme's understanding of what kind of thing <object> is. Returns <object>, with its new tag. Warning: Misuse of this function will cause Wraith Scheme to crash. (Indeed, almost any use of this function will cause Wraith Scheme to crash.)

    (e::show-dynamic-environment-list)
    

      Shows all symbols, and their values (if any), that are visible in the lexical scope from which this procedure was called, except for those in the top-level environment. Returns #t. The display will consist of a sequence of several similar displays. The first one will show all symbols in the innermost lexical scope visible to the caller, then the next innermost lexical scope, and so on out to, but not including, the top-level, "global" environment.

    (e::show-environment)
    

      Shows all symbols, and their values (if any), that are visible in the innermost lexical scope from which this procedure was called. Returns #t.

    (e::show-environment-list)
    

      Shows all symbols and their values (if any) that are visible in the lexical scope from which this procedure was called. Returns #t. The display will consist of a sequence of several similar displays. The first one will show all symbols in the innermost lexical scope visible to the caller, then the next innermost lexical scope, and so on to the top-level, or "global" environment. This last display will be extremely lengthy, for it will include all the Wraith Scheme primitives, like "+", "car" and "cons".

    (e::show-memory)
    

      Shows an extremely lengthy display of all objects in the main memory presently used by Wraith Scheme. Returns #t.

      Fair warning: If you call this procedure when Wraith Scheme is using a large main memory -- say a Gigabyte -- and if that memory is full, or nearly so, the procedure may well attempt to generate a hundred million lines of output.

    (e::show-stack)
    

      Shows the contents of the internal stack used by Wraith Scheme. Returns #t. This stack is different from the "machine stack", and has nothing to do with any microprocessor "stack" register. Also see the procedure "e::write-stack".

    (e::stack-depth)
    

      Returns an integer, which is the number of objects on Wraith Scheme's internal stack.

    (e::write-continuation)
    

      Writes out the current continuation as a list. Returns #t. I use "continuation" here in the sense of the 'C' register of an SECD machine.

    (e::write-stack)
    

      Writes out the contents of Wraith Scheme's internal stack as a list, with the most recent object pushed as the car. Returns #t. Also see the procedure "e::show-stack".

  • Top-Level Control:

    Several procedures allow top-level control of the operation of the Wraith Scheme application:

    (e::exit)
    

      Causes Wraith Scheme to terminate. It's how you get back to (e. g.) the Finder. The "e::exit" procedure can also be invoked via the "Quit" command or the "Quit" menu item, or by clicking on the red "close window" widget -- the little red dot -- at top left in the Wraith Scheme Window.

      In Wraith Scheme parallel processing, the MomCat is essential: Thus when you terminate the MomCat by any of these means, Wraith Scheme will also terminate all other Wraith Scheme processes -- all the kittens -- that are running. That is, in the MomCat, "e::exit", the "Quit" command, the "Quit" menu item, and the little red dot all act as global "kill" commands for all Wraith Scheme processes that you are running.

      When you use the "Quit" command or menu item, or click on the "close window" widget, Wraith Scheme will ask you to confirm that you really want to exit. (Otherwise a simple error -- perhaps accidentally picking the wrong menu item, could lose of a lot of work.) But when you evaluate "(e::exit)" in the Wraith Scheme window, or in a program, there will be no dialog, the program will just quit.

    (e::reset)
    

      Stops whatever Wraith Scheme is doing, and returns control to you. You can also invoke the "e::reset" procedure from the "Reset to Top-Level Loop" menu item or the corresponding keyboard command, "Control-Option-Command-Delete". If Wraith Scheme is doing the "wrong thing" -- perhaps a program has entered an infinite loop -- the keyboard and menu commands will force execution to halt. Within a Scheme program, "e::reset" is useful for error handling, as a way to stop execution without returning some kind of error flag back through many procedure calls.

    (e::set-input-port!)  ;; With no argument, uses a dialog.
    (e::set-input-port! <string with a path to a file>)
    

      "e::set-input-port!" is a procedure that only a developer could love. It makes a permanent change in where the system gets its top-level input. Its intended use is in testing error-handling, in the following way: When "e::reset" is evaluated, it normally returns control to the Wraith Scheme window, so that the next input to Wraith Scheme after an "e::reset" evaluation is whatever is next typed into the window. But if "e::set-input-port!" has been called, then the next input after the reset will be taken from the port passed to "e::set-input-port!". Thus to perform many tests of a program that calls "e::reset" for error handling, you might create a text file containing those tests, enter Wraith Scheme, open a transcript, and call "e::set-input-port!" with the name of that text file. The tests will start to run, and when "e::reset" is called, Wraith Scheme will perform the next test in the file, instead of returning control to the Wraith Scheme window.

      Note that you cannot use "load" instead of "e::set-input-port!" for the same effect: If "e::reset" were called by any of the forms being loaded, then the "load" procedure itself would terminate immediately, and control would return to the Wraith Scheme window.

      This procedure will only work correctly when called from top-level; in particular, it will not work when called by code that is being executed via the "load" procedure.

    (c::disable-window-output)
    (c::enable-window-output)
    (c::window-output-enabled?)
    

      These procedures allow you to control whether Wraith Scheme writes output to the Wraith Scheme window or not. The first two respectively disable and enable that output, the third returns a boolean indicating whether output is enabled or not.

      Output to files, including transcript files, is not affected by these procedures. Furthermore, anything you type into the Wraith Scheme Input Panel will be echoed in the Wraith Scheme window, even if window output is disabled.

      These procedures use the same mechanism to control window output as does the "Disable Window Output" menu item, in the Interpreter Menu, but the procedures do not cause display of the panel that drops down from the top of the Wraith Scheme window to remind you that output is disabled.

    One procedure causes Wraith Scheme to crash:

    (c::down-in-flames!!!)
    

      DANGER!! This procedure causes Wraith Scheme to fail. (If not, it's a bug.)

      I created this procedure so that I could easily test Wraith Scheme's mechanism for reporting fatal errors.

  • World Saves and Loads:

    (e::load-world! <string naming a file>)
    (e::load-world!)
    

      Only the MomCat may execute this procedure.

      Loads a "saved world" file, which contains most of what was known to Wraith Scheme when the file was created. If no file name is given, puts up a standard dialog box for selecting a file, and also displays a message telling what world was loaded. Returns #t. Returns control to the top-level loop after the world is loaded, even if the procedure was called from deep within another procedure.

      This procedure overwrites everything in Wraith Scheme's memory!

      In particular, if you load a world from within a Scheme program, the program will stop executing immediately after the load. If you use the "load" procedure to load a file of Scheme code, and that file loads a world, then nothing more will be read from the file after the world load, because the "load" procedure itself will have stopped.

    (e::save-world <string naming a file>)
    (e::save-world)
    

      Only the MomCat may execute this procedure.

      Creates a special "saved world" file, that contains almost everything known to Wraith Scheme when the file is created. If no file name is given, puts up a standard file dialog box for selecting a file. Returns #t. This procedure does not overwrite any objects.

    It usually makes sense to save and load worlds only from top-level in Wraith Scheme, not from the middle of programs that are running: A saved world does not preserve the contents of Wraith Scheme's stack or continuation, or any of the other data that would be required to pick up in the middle of an executing program. Thus a saved world contains only a top-level environment: Once that environment is reloaded, you must evaluate an expression manually to get things to start happening.

    In any case, a world load does a reset immediately after completing the load. You will then be back at top-level, even if the world was saved from within a program, or even if you called "e::load-world!" from within an executing program.

    Saved worlds can be loaded only into the specific version and release of Wraith Scheme from which they were originally saved.

    Wraith Scheme is a universal binary application; that is, it can run on Macintoshes that use either Intel microprocessors or PowerPC microprocessors. You might wonder whether world files created by Wraith Scheme running on one kind of Macintosh can be loaded by Wraith Scheme running on the other kind of Macintosh. The answer is "yes"; there is only one kind of Wraith Scheme world file, which can be read and written equally well by either kind of Macintosh.

Quarantined Short Flonums:

Wraith Scheme uses IEEE 32-bit flonums internally in a special way: Informally, they are highly "contagious", but they are "quarantined" in the sense that it if you do not explicitly introduce IEEE 32-bit flonums to a mathematical procedure, that procedure will not produce any IEEE 32-bit flonums on its own. That kind of isolation may be desirable, because although IEEE 64-bit flonums provide more precision than do IEEE 32-bit flonums, they also use a lot more memory.

In more detail:

  • The only external representation of a number which will cause Wraith Scheme to store the number as an IEEE 32-bit flonum is one which uses the non-standard exponent marker "q" (or "Q"). Think "Q for Quarantined". This exponent marker may be used wherever the standard Scheme exponent markers -- "d", "e", "f", "l", and "s" -- might be used, and with similar effect on exactness. For example:

      1q0           ;; Stores inexact 1 as an IEEE 32-bit flonum.
      #e1q0         ;; Stores exact 1 as an IEEE 32-bit flonum.
      -10000q0      ;; Stores inexact -10,000 as an IEEE 32-bit flonum.
      #e123.5q0     ;; Stores exact 123.5 ...
      6.024q23      ;; ...
      

  • If Wraith Scheme encounters an external representation of a number, that includes a "q" exponent marker, that is out of range for an IEEE 32-bit flonum, Wraith Scheme will store the number indicated as an IEEE 32-bit infinity; Wraith Scheme will not coerce the number to any other storage form.

  • If any operand of a mathematical operation is stored as an IEEE 32-bit flonum, Wraith Scheme will return a result that is stored as an IEEE 32-bit flonum. Wraith Scheme will never coerce the result of such an operation to any other form of storage. In particular, even if the result of such an operation is outside the range of IEEE 32-bit flonums but within the range of IEEE 64-bit flonums, Wraith Scheme will return an IEEE 32-bit infinity, not an IEEE 64-bit flonum. In particular, even if the result of such an operation is an integer in the range that can be represented as 32-bit fixnums, Wraith Scheme will return an IEEE 32-bit flonum, not a 32-bit fixnum.

  • In base 10, the procedure "number->string" will always print IEEE 32-bit flonums using a "q" exponent marker. For example:

      (number->string 1q0)       ;; ==> "1.q0"
      (number->string 0q0)       ;; ==> "0q0"
      (number->string 0.0001q0)  ;; ==> "1.000000q-4"
      (number->string 1.234q30)  ;; ==> "1.2340000q30"
      

  • In base 10, the procedure "number->string" will print a decimal point in the external representation of an IEEE 32-bit flonum that is inexact. For example:

      (number->string 1.q0)   ;; ==> "1.q0"
      (number->string #i1q0)  ;; ==> "1.q0"
      

  • In base 10, the procedure "number->string" will either refrain from printing a decimal point, or print an explicit exact prefix ("#e"), or both, in the external representation of an IEEE 32-bit flonum that is exact. For example:

      (number->string #e.1q0)      ;; ==> "1q0"
      (number->string #e0.0001q0)  ;; ==> "#e1.000000q-4"
      

  • In bases other than 10, if the procedure "number->string" is able to print an IEEE 32-bit flonum (that is, if the flonum happens to be an integer), it will not print an exponent marker; there will be no indication that the internal representation of the number passed to "number->string" was an IEEE 32-bit flonum. For example:

      (number->string #e255q0 16)  ;; ==> "ff"
      (number->string 255q0 16)    ;; ==> "#iff"
      

The intent of this enhancement is to permit mathematical procedures to calculate solely with IEEE 32-bit flonums. Without some such enhancement, the usual rules of IEEE 64-bit flonum contagion make it all too easy for a procedure that starts out using only IEEE 32-bit flonums, soon to find itself using IEEE 64-bit flonums almost exclusively. Unfortunately, IEEE 64-bit flonums use a great deal more storage than do IEEE 32-bit flonums: Wraith scheme requires 28 bytes to store an IEEE 64-bit flonum, but only 8 bytes to store an IEEE 32-bit flonum. Therefore, IEEE 64-bit flonum contagion may lead to excessive use of memory.

Thus the "quarantined short flonums" enhancement allows you to make the tradeoff between numeric precision and memory use as you see fit. If you want high precision, provide your mathematical procedures with only inputs that are not IEEE 32-bit numbers, and you will obtain IEEE 64-bit precision. If you would rather minimize memory use, provide your mathematical procedures with IEEE 32-bit inputs, and you will achieve greater parsimony of storage.

You may use Wraith Scheme without encountering this enhancement if you do not use the exponent marker "q" in numeric input.

Top-Level Loop Variables:

Like Common Lisp, Wraith Scheme maintains several variables that may prove handy should you forget to save an interesting input expression or output result. Their names are closely related to the names of similar variables used in Common Lisp.

    Common Lisp    Wraith Scheme
    ===========    =============
        -              >-<
        +              >+<
        ++             >++<
        +++            >+++<
        *              >*<
        **             >**<
        ***            >***<
    

Wraith Scheme cannot use the exact same variable names as Common Lisp, because there is only one namespace in Scheme, and the symbols "+", "-" and "*" are already bound to the procedures for addition, subtraction and multiplication.

If you use Wraith Scheme's parallel processing enhancements, you will find that each kitten has its own variant of these variables. See the parallel-processing section on Keeping Track of Things for details.

When Wraith Scheme starts running, these variables are all initialized to the empty list.

    >+<
    >++<
    >+++<
    

While a Scheme S-expression is being evaluated by the top-level loop, the variable >+< is bound to the previous form that was read by the loop. The variable >++< is bound to the previous value of >+< (that is, the form evaluated two interactions ago), and >+++< is bound to the previous value of >++<.

    >-<
    

While a Scheme S-expression is being evaluated by the top-level loop, the variable >-< is bound to the S-expression itself; that is, to the value that will be bound to >+< once the current interaction is complete.

    >*<
    >**<
    >***<
    

While a Scheme S-expression is being evaluated by the top-level loop, the variable >*< is bound to the result that was printed at the end of the last time through the loop; that is, to the value that was produced by evaluating the S-expression in >+< The variable >**< is bound to the previous value of >*< (that is, to the result from the form evaluated two interactions ago), and >***< is bound to the previous value of >**<.

If the evaluation of >-< is aborted, then the values bound to >*<, >**<, and >***< are not updated; they are updated only if the printing of the value, returned from evaluating >-<, has begun.

The utility of these variables somewhat overlaps the utility of the command-history and scrolling mechanisms available in the Input Panel and in the Main Display Panel.

Kittens -- Parallel Processing in Wraith Scheme:

WARNING:

  • The Wraith Scheme enhancements for parallel processing are:

    • Experimental,

    • Subject to change,

    • Probably full of bugs.

    It is therefore most important to note that

    • You don't have to use them!

    Indeed, Wraith Scheme's default preferences are set up so that Wraith Scheme will run as a single process until and unless you request otherwise.

    If you should decide to use Wraith Scheme's enhancements for parallel processing, I encourage you to do so only in circumstances in which you can afford to be both cautious and tolerant.

Introduction to Wraith Scheme Parallel Processing:

  • Wraith Scheme has the ability to run a small number of separate Scheme processes, each with its own Macintosh-style user interface, evaluation engine, and the like, but all sharing the same Scheme memory.

      Technical Note: That's separate processes, not separate threads. Yet confusingly enough, each individual Wraith Scheme process does uses several separate threads.

  • There is one privileged process which controls -- or at least supervises -- several aspects of Scheme-memory management that were not easy to run in parallel, most notably including garbage collection. Furthermore, only that privileged process can load or save worlds, modify Preferences, and load startup files, and only the privileged process can automatically load a file when it has been updated.

    Since Wraith Scheme is named after a cat, I decided to continue the feline metaphor. The privileged Scheme process is called the "MomCat", and the others are called "kittens". The image of a mother cat trying to ride herd on a bunch of rambunctious offspring is perhaps appropriate.

      Non-Technical Note: A friend of mine once claimed to have a fifth-degree black belt in the little known Japanese martial art of nekobana -- which means "cat arranging". Programmers will be familiar with the skill required. Managers of programmers will be extremely familiar with that skill.

  • At present, the maximum number of separate Scheme processes allowed is sixteen -- one MomCat, plus up to fifteen kittens. The number of kittens is determined from the Wraith Scheme Preferences when Wraith Scheme starts up, and the "Preferences" panel has been enhanced to include a setting for the number of kittens.

    There is no way to add kittens to a group of parallel Wraith Scheme processes that is already running. You may remove a kitten from a group via, e.g., the "Quit" command from that kitten's Wraith Scheme menu, but there is no means to put back a kitten that is gone, or to add a new one if you need more, other than changing the Wraith Scheme Preferences and restarting Wraith Scheme.

    Each kitten has a number that identifies it uniquely. The MomCat also has a kitten number, which is always zero, and the terms "MomCat" and "kitten 0" are synonyms. The other kittens are numbered consecutively from 1.

  • Parallel processing is entirely optional: If you do not want to use it, set the number of kittens to zero by means of the Wraith Scheme Preferences, and Wraith Scheme will run as a single process -- just the MomCat.

Background, Philosophy and Intent:

    It is probably fair to say that one of the main reasons why I added a parallel processing capability to Wraith Scheme was just because I thought it would be a neat thing to do. Notwithstanding, a few additional comments might offer useful guidance if you are contemplating using this capability.

    • To begin with, remember that the capability is real, not simulated: The separate Wraith Scheme user interfaces actually do connect to distinct Unix processes, each of which is a separately running instance of the Wraith Scheme program. On Macintoshes with more than one processor core, more than one of these processes may be running at the same time.

    • The capability is intended to be a natural match for the degree of hardware parallelism we are likely to see in Macintoshes during the next few years (but your crystal ball may offer different predictions): As I write these words, in October, 2007, my own Macbook has two processor cores, and the highest-end Mac Pro has eight. Sixteen Wraith Scheme processes sounds like about the right number to keep eight cores busy -- and the internal program architecture that I have used to implement parallel processing will easily scale to several times as many kittens.

    • The parallelism is thereby probably best-suited to coarse-grained uses: Sixteen processes is not a lot, and low-end Macintoshes probably will not get any performance benefits from using that many processes anyway. Folks used to processing arrays on single-instruction, multiple-data machines with tens of thousands of processors, or to searching the web with hundreds of separate machines linked by Ethernet, may find their preferred parallel-programming paradigms inappropriate for Wraith Scheme.

      Plausible uses for parallel Wraith Scheme might include running completely separate programs, running distinct programs which all need to act on a common data structure, or using one Wraith Scheme process to inspect or monitor another.

      Among the hidden virtues of this kind of parallelism are reduction in swapping due to sharing a common Scheme memory, and leveraging the Unix mechanisms to switch and schedule processes instead of having to write your own.

    • The programs run by separate kittens are assumed to be friendly to one another, in the sense that they are all assumed to be written and operated by one user who has no interest in in shooting himself or herself in the foot: Thus although the parallel implementation takes low-level measures to maintain the integrity of its own private, internal data structures, there is nothing like a firewall or a security layer protecting the separate Wraith Scheme processes from one another. So if you want to crash your own program, or overwrite or steal your own data, go right ahead; there is more than enough firepower available to shoot yourself in as many feet as you are likely to possess, and then some.

        Technical Note: By "low-level measures", I mean, for example, that I have attempted to maintain heap integrity by blocking conflicting simultaneous writes.

        Thus, for example, if two or more kittens apply "set!" to the variable "x" at more or less the same time, the value of "x" after all the "set!" operations have returned will be a value that one of the kittens intended, but in the absence of additional locking or sequencing mechanisms imposed by the user, there is no guarantee which of the several values of "x" will obtain.

        On the other hand, the storage location referenced by "x" should not end up in an invalid state, such as might occur if different portions of the data structure at that storage location had ended up written by different kittens, who were perhaps attempting to write different kinds of values at more or less the same time.

        Operations like "define", "set-car!", and "set-cdr!" -- indeed, everything that ends with a '!', and some others -- are similarly protected; that is, from the viewpoint of the Wraith Scheme evaluation engine, they are what is called atomic operations.

    • Wraith Scheme provides a number of low-level primitive procedures useful for locking data structures against parallel access and for interprocess communication, but it is up to the user to decide what to construct with these building blocks.

Keeping Track of Things:

  • Procedures and variables useful for keeping track of the simpler details of a running group of parallel Wraith Scheme processes include:

     (e::kitten-number) 

      Returns the number of the kitten in which the procedure was called. The MomCat has a kitten number of zero; the kittens, if any, have kitten numbers from one up to and including the value returned by "e::number-of-kittens".

     (c:kitten-reset <kitten-number>) 

      Resets the given kitten: Causes the same effect as the "Reset to Top-Level Loop" command, for the kitten indicated.

    (e::momcat?)
    

      Returns whether or not it was called in the MomCat.

    (e::number-of-kittens)
    

      Returns the number of kittens that were present when the group of parallel Wraith Scheme processes was started, not counting the MomCat. This number does not change if a kitten exits, as it might if you used its "Quit" command.

      Thus if you start a group of Wraith Scheme processes comprising a MomCat and five kittens, "e::number-of-kittens" returns five, and the kittens are numbered from zero -- the MomCat -- up to and including five.

    (e::show-kittens)
    

      Displays some details about each kitten, in human-readable form.

  • To each top-level loop variable used by the MomCat corresponds a group of variables with similar names and similar functions -- one for each kitten. The names for the top-level loop variables for kitten "N" are constructed by appending "-N" to the corresponding name used in the MomCat. Thus for example, to the MomCat's variable ">+<" corresponds the variables ">+<-1", ">+<-2", ">+<-3", ">+<-4", and so on, in kittens 1, 2, 3, 4, and so on, and similarly for the other six top-level loop variables used by the MomCat.

    I am not going to list the names of all these variables; there are too many.

    Note that you may access any top-level loop variable from any process, not just from the process whose top-level loop binds the variable. Thus for example, if kitten 3 wishes to know what the last expression printed in kitten 5's top-level loop was, it may evaluate ">*<-5" to find out.

  • Each kitten's Wraith Scheme window has a different color, and its icon in the Macintosh dock is colored to match. Furthermore, the title of each Wraith Scheme window shows whether the corresponding process is the MomCat or one of the kittens. The result verges on terminal cuteness ...

    Colored Windows

    Reduced-size Macintosh screen image with colored Wraith Scheme kitten windows.
    Note the colored kitten icons to the right of center in the dock.

  • The Wraith Scheme Window Menu has been enhanced with the "Bring Kitten to Front" menu item: It opens a submenu showing all of the Wraith Scheme processes that are running -- both MomCat and kittens. Choosing an item on this submenu brings the Wraith Scheme window of that process to the front of the display. This menu item is useful when there are many Wraith Scheme processes running at the same time.

Interprocess Communication:

  • Procedures and other means for interprocess communication include:
    (e::tell-kitten <kitten-number> <any Scheme object>)
    

      This procedure provides access to an input queue mechanism whereby any kitten may provide input for the top-level read-eval-print loop of any kitten, even itself.

      To see how the mechanism works, consider the normal operation of a conventional top-level read-eval-print loop. In psuedocode, and neglecting error-handling and some administrative details, it works like this:

        loop forever {
            read from the keyboard, characters which are
                the text representation of a Scheme object.
            parse the input and create a corresponding actual
                Scheme object -- perhaps an S-expression or
                an atom -- stored in Scheme memory.
            evaluate what you've got.
            print what results.
            }
        
      In the parallel implementation of Wraith Scheme, the idea is to deal with stuff in the input queue before dealing with anything the user has typed at the keyboard. A little more specifically, the psuedocode looks like this:
        loop forever {
            loop forever {
                if there is anything in the input queue {
                    dequeue the item first put in
                    exit the inner loop.
                    }
                if the user has typed any non-whitespace {
                    read from the keyboard, characters which
                        are the text representation of a
                        Scheme object.
                    parse the input and create a corresponding
                        actual Scheme object -- perhaps an
                        S-expression or an atom -- stored in
                        Scheme memory.
                    exit the inner loop.
                    }
                }
            evaluate what you've got.
            print what results.
            }
        

      Note that the contents of the queue are not text strings, but Scheme objects which have already been parsed and evaluated.

      For example:

        (e::tell-kitten 1 '(+ 2 2))
        

      puts into the input queue for kitten one the Scheme object (quote (+ 2 2)). When kitten one gets around to dealing with that queued object, it evaluates it -- to the number "4" -- and prints the text string "4" in its Wraith Scheme window. On the other hand, without the quote, the action is rather different. In the process of the procedure call:

        (e::tell-kitten 1 (+ 2 2))
        

      the argument "(+ 2 2)" is evaluated before the procedure is called. Thus what ends up in kitten one's input queue is the object "4" itself -- the work of evaluation has already been done.

      The message here is that in order to make sure that the kitten addressed does the work, remember to quote the Scheme object that is the second argument of "e::tell-kitten".

      The "e::tell-kitten" procedure is atomic, in the sense that no garbling or missing objects will arise if more than one kitten uses the procedure with the same first argument at the same time; for example, if kitten 1 executes

        (e::tell-kitten 3 (+ 2 2))
        
      at the same time that kitten 2 executes
        (e::tell-kitten 3 (+ 4 5))
        
      then kitten three will receive both commands in one order or the other, and will print out both 4 and 9 in its Wraith Scheme window in one order or the other.

      A reset of any kind -- whether because of an error or because of use of the "Reset" command -- clears the input queue of the kitten that was reset.

    (c::kitten-input-queue <kitten-number>)
    

      This procedure returns the current content of the input queue of the kitten indicated.

    (c::kitten-empty-queue? <kitten-number>)
    

      This procedure returns a boolean indicating whether the input queue of the kitten indicated is empty.

    (c::kitten-purge-queue <kitten-number>)
    

      This procedure clears the input queue of the kitten indicated.

File System Access:

    Since each Wraith Scheme kitten is a separate Unix process, each kitten maintains its own separate data structures for access to the Unix file system. The mechanisms that Wraith Scheme uses to create and manipulate ports have no way to allow one kitten to have direct access to another kitten's file-system data structures; thus you may only read from or write to a Wraith Scheme port from the kitten that created it.

Locks and Critical Sections:

  • Procedures useful for low-level handling of critical sections in Wraith Scheme include:

    (c::block <Scheme object in main memory>)
    

      Arranges that any attempt to use or modify the object hangs in a loop until the lock is released.

    (c::release-block <locked Scheme object in main memory>)
    

      Releases any lock that may have been established on its argument.

    (e::block-symbol-binding <symbol>)
    

      Arranges that any attempt to use or modify the value bound to the symbol hangs in a loop until the lock is released, with the exception that modification by means of "c::set-blocked-binding!" is permitted.

    (c::set-blocked-binding! <lock from e::block-symbol-binding> <object>)
    

      Change the value bound to the (otherwise locked) symbol to the new object given.

    For more detailed examples of the use of these procedures, see their entries in Wraith Scheme Dictionary, which is available via the Wraith Scheme Help menu.

Aids to Debugging:

    Mechanisms useful for debugging parallel Wraith Scheme programs include:

  • Extra kittens:

    It is extremely useful to have at least one more kitten operating than your Scheme program actually needs, to use as a debugging or monitoring window into how things are going. You can use such a kitten -- that is, you can perform Scheme operations in its Wraith Scheme window -- to examine your program, even as it runs: You can check the value of global data, evaluate expressions, and perhaps use other self-monitoring features of your program that you yourself have built in.

  • Top-level loop variables:

    Among the variables you might choose to evaluate in the Wraith Scheme window of an extra kitten might be the top-level loop variables of the kittens that are actually running your program.

  • Procedures:

    (e::show-locks)
    

      Provides a low-level description of every locked object in Scheme main memory, and of the state of locking of bins of the hash tables used to control access to Wraith Scheme's oblist and top-level environment.

      This procedure is deceptive, because other kittens may be setting and releasing locks as it runs: The state of locks displayed may not be current moments later.

    (c::release-locks)
    

      Provides the same display of locked objects that "e::show-locks" does, and then releases every lock that it found.

      This procedure is dangerous and deceptive, for several reasons:

      • Other kittens may be setting and releasing locks as it runs: The state of locks displayed may not be current moments later.

      • Willy-nilly release of locks may cause Wraith Scheme to crash or hang.

      • If an inappropriate lock has made your Scheme program unresponsive, releasing that lock probably will not restore normal behavior; the most it is likely to do is make it easier to investigate the bugs. Thus perhaps there is some important data in your program, that you need to study to determine what the problem is, only you cannot get to it, even to display it, because of a lock. In that case, releasing locks may be profitable, provided that Wraith Scheme doesn't crash or hang.

      An analogy with medical practice may be useful: Releasing locks is unlikely to cure a sick patient, but it may help prepare the cadaver for autopsy, provided that it doesn't blow up the morgue in the process.

    (c::let-deadlock-time-out <a kitten number>)
    

      This procedure provides a way to debug circumstances in which kitten is trying to lock access to a Wraith Scheme object that is already locked, and has remained locked for a worrisome amount of time. The "worrisome amount of time" is guaranteed to be at least 0.01 seconds, but may be longer, depending on the speed of your Macintosh and on what else -- other than Wraith Scheme -- it is doing.

      This procedure does not apply to locks of bins of the hash tables used to control access to Wraith Scheme's oblist and top-level environment.

      If the kitten whose kitten number is passed to the procedure has been trying to obtain access to a locked object for more than the "worrisome amount of time" just described, this procedure will cause it to give up trying, print out some information about what it was attempting to lock, and reset to top-level.

      This procedure may be applied to any kitten and called from any kitten.

      This procedure is dangerous, because release of deadlocks may cause Wraith Scheme to crash or hang.

      Once again, by analogy with medical practice, this procedure is a post-mortem diagnostic tool, not a cure for the patient.

Auxiliary Files:

    The mechanism for sharing memory between a Wraith Scheme MomCat and her kittens requires several auxiliary files. There are four of them, and they are all in the "Wraith Scheme" folder of the "Application Support" folder of the "Library" folder of the user who is running Wraith Scheme. That is, if your user folder should happen to be named "JayFreeman", those files will appear in the folder whose Unix path is

      /Users/JayFreeman/Library/Application Support/Wraith Scheme

    The names of those files are:

      Wraith Scheme Clowder
      Wraith Scheme Scratch Stack
      Wraith Scheme Space A
      Wraith Scheme Space B

    Do not delete or modify any of these files while Wraith Scheme is running! Doing so will cause Wraith Scheme to crash.

      Technical Note: These files provide a place where the operating system can swap out portions of the shared memory that are temporarily not in use. The first file contains a variety of items used for communication between the various Wraith Scheme processes. (Note that a "clowder" is a colony of cats.) The second file is scratch space where each Wraith Scheme process in turn may dump its Scheme stack during garbage collection. The remaining two are for Wraith Scheme's two Scheme memories.

    In normal operation, Wraith Scheme will remove these files when the MomCat exits, for there is then no further need for them. If Wraith Scheme should crash, or otherwise exit abnormally, the files may escape deletion. When Wraith Scheme is not running, you may safely remove any of these files that you find, if you wish. Wraith Scheme will in any case delete any old copies of the files that it finds, the next time it starts up.

    The total size of these files is somewhat more than twice as large as the amount of memory that Wraith Scheme uses for Scheme memory.

Optimizations:

    There are a couple of optimization techniques involving Wraith Scheme's parallel processing capability, that you might want to know about.

    First, the locking mechanisms that maintain the integrity of Wraith Scheme main memory when several processes are active, are disabled when you start up Wraith Scheme with just the MomCat. The locking mechanisms are intrinsically slow, so if you only need to run code in one Wraith Scheme window, your Scheme programs will run much faster if you start up Wraith Scheme to use only one process.

      Technical Note: The big hit in the time required for locks is "memory barrier" operations.

    Second, items in Wraith Scheme main memory can be read faster when they are being read by the Wraith Scheme process that most recently used them -- that is, the process that has most recently read, written or modified them -- than when they are being read by some other Wraith Scheme process. Thus for example, it makes sense to load files, create top-level data items, and do compilations, in the Wraith Scheme window that will most often use the code and data items thereby created, and it makes sense to perform repeated calculations on a single data structure in a single Wraith Scheme process.

    Third, with an eye toward the day when Non-Uniform Memory-Access (NUMA) computers become more common, Wraith Scheme's garbage-collection mechanism attempts to group items in Wraith Scheme main memory according to which Wraith Scheme process has most recently used them -- that is, the process that has most recently read, written or modified them. The assumption here is that a process that has recently used a particular item is likely to use it again: Thus, improving the localization of items in Wraith Scheme main memory may allow even a simple NUMA page-placement algorithm to preposition data used by a particular process so that it is close (in the NUMA sense) to where that process is executing, and thereby save memory-access time. At any rate, such is my pious hope. (Note, however, that Wraith Scheme will not break apart a cdr-coded list whose various members have been most recently used by different kittens.)

    Fourth, the locking mechanisms that Wraith Scheme uses to protect the integrity of Wraith Scheme main memory are not used for Scheme code which is being run. That is not to say that you cannot modify Scheme code -- lambda bodies, procedure applications, and the like -- for you certainly can, but if one Wraith Scheme kitten attempts to modify code which a different kitten is in the act of running, a crash of one or both kittens is likely.

      Technical Note: That is, the Wraith Scheme continuation is both loaded and read without using such locks.

A Final Word of Caution:

  • Once again, let me mention that Wraith Scheme's enhancements for parallel processing are experimental, subject to change, and probably full of bugs.

Easter Eggs:

In computer slang, an "Easter Egg" is a program feature that is cute or useful but perhaps temperamental or obscure. "Obscure" means that the feature is poorly documented or even not documented at all, and is unlikely to be stumbled upon by chance. There are likely to be features that fit this definition in every release of Wraith Scheme, if only for the following reasons:

  • I may have put in a feature to aid in the development and release process itself -- something that only a developer would love or use.

  • I may have been working on a new feature, to be explained and documented subsequently, that wasn't quite ready when I decided to release a new version of Wraith Scheme.

  • I like cute.

You might wonder why I don't just disable such features for a release. The reason is that disabling one part of a program often breaks another. It's kind of like do-it-yourself plumbing repair, or maybe like trying to pull a "loose thread" off a garment you are wearing: The consequences may be disastrous. Wraith Scheme will be much more stable if I just leave such features in.

Anyhow, here are some of the Easter Eggs in Wraith Scheme.

  • Running Wraith Scheme from a Unix Shell:

    This feature will make sense only to those of you who know how to use a Unix shell. Furthermore, this feature may not be as useful as you are hoping for: Mostly, it provides a way for Wraith Scheme to load and execute files of Scheme code under control of Unix shell scripts and the like. If that sounds useful, keep reading ...

    To run Wraith Scheme from a Unix command line, open a window of the "Terminal" application, and enter the path to the Wraith Scheme executable. The problems are finding the actual executable, and figuring out how to use a Unix path that contains blank spaces. Let me remind you how to do those things.

    The actual Unix executable for Wraith Scheme is buried deep within the "application" -- the thing with the Wraith Scheme icon -- that shows up in Macintosh Finder windows. (That's how Macintosh applications work, it's not just something weird that I put in.) For example, suppose you have placed the Wraith Scheme application in your "Applications" folder. Then the full path to the Unix executable, presented here with sufficient quotation marks for the Unix shell to understand it, is:

      /Applications/"Wraith Scheme.app"/Contents/MacOS/"Wraith Scheme"

    So what you would type at the command prompt, in a Macintosh Terminal window, using the (default) "bash" shell, to get Wraith Scheme going, is

      /Applications/"Wraith Scheme.app"/Contents/MacOS/"Wraith Scheme"

    All that does is start the program going, just as if you had clicked on its icon in the Finder, but there's more: Wraith Scheme has a command-line flag that makes it use the Terminal window for input and output. The flag is "-t". (There are some more flags; I will get to them in a few paragraphs.) At the command prompt, enter:

      /Applications/"Wraith Scheme.app"/Contents/MacOS/"Wraith Scheme" -t

    The usual Wraith Scheme window will open, but all the text that Wraith Scheme would normally have printed to the Main Display Panel will instead be printed in the terminal window, and instead of entering Scheme commands into the Input Panel you will need to type them into the terminal window.

    Unfortunately, the "-t" flag does not quite turn Wraith Scheme into a program that behaves well in a Unix shell. There are several gotchas:

    • When you start Wraith Scheme from a Unix prompt, you must provide the full Unix path, as shown in the examples above. Relative paths will not work -- Wraith Scheme will run, but it won't be able to find the world that it is supposed to load at startup. (You could load the world yourself, if you wished, but it is probably easier just to type the full pathname.)

    • Output to the terminal shell will be a bit garbled -- there won't be enough "return" characters sent to the shell for everything to look tidy. The results of running a Scheme command will probably start on the same line where the command ended, instead of starting on a new line.

    • You will have to use the regular Wraith Scheme window for anything you can't do from the Input Panel. Most notably, that includes resetting to the top-level loop. It also includes any use of the Dialog Panel or the Message Panel.

    I created this feature so that I could run Wraith Scheme and load files of Scheme source code from a Unix shell script or makefile. I have thereby automated testing of Wraith Scheme. My test scripts consist of a long series of shell commands or makefile commands that look something like this:

      echo "(load <path to a test file>)" | /<path to the executable>/"Wraith Scheme" -t <more flags>

    All that does is start Wraith Scheme running, with whatever additional command-line flags are provided, and send it the single command:

      (load <path to a test file>)

    (Note that the Unix "echo" command adds the necessary "newline".)

    My files of test code use the Scheme "transcript-on" and "transcript-off" procedures to record output in a file; those work fine -- output is not garbled -- with the "-t" flag.

    Other flags useful in connection with "-t" are:

    • -c < 0 or 1 > -- for 1, set the internal Wraith Scheme compile-defines flag; for 0, clear it. (Otherwise, the value of the flag is taken from the Wraith Scheme preferences.)

    • -m <integer> -- set the Wraith Scheme main memory size to the number of MByte specified by the integer. That is, "-m 20" indicates a main memory size of 20 MByte. (Otherwise, the memory size is taken from the Wraith Scheme preferences.)

    • -z <integer> -- create the number of kittens specified by the integer. The number specified does not include the MomCat; for example, "-z 3" causes Wraith Scheme to run with four processes -- a MomCat and three kittens. (Otherwise, the number of kittens is taken from the Wraith Scheme preferences.)

  • Meow:

    If you haven't figured out by now what happens when you click on the little panel at the top right corner of the Wraith Scheme window, you should try it ...

  • The Sock Drawer:

    Wraith Scheme has a "drawer" that opens on the right side of the Wraith Scheme window, temporarily called "The Sock Drawer", accessed by a menu item in the Wraith Scheme "Window" menu. That drawer presently has no function and contains nothing but darkness. It will probably do something interesting or useful -- maybe even both -- in a future release.

  • Unusual Icon Appearance:

    Now and then the Wraith Scheme icon may look a little different ...

  • Cat-Like Behavior:

    Every so often, Wraith Scheme may undertake some harmless cat-like behavior ...

Bugs, Flaws, Limitations, and Dealing with Them:

I am sure Wraith Scheme contains bugs, and I want to hear about them so that I can fix them.

My EMail address is Jay_Reynolds_Freeman@mac.com.

If you cannot reach me by EMail, try paper mail to

    Jay Reynolds Freeman
    Post Office Box 60628
    Palo Alto, CA, 94306-0628
    U. S. A.

If you ever encounter a fatal or non-fatal error with a message like

    "Implementation error ..."
    

or

    "Implementation: ..."
    

then I would much appreciate a bug report with as many details as you can provide. (In particular, include the entire message.) Such errors indicate that I have inadequately guarded against some anticipatable problem: It's my fault; I will be eager to do better.

Known Bugs and Flaws:

The only reason I will release a distribution of Wraith Scheme containing a known bug or a glaring flaw is that there is some reason I cannot fix the problem. At present:

  • Insert-Point Glitchiness:

    Sometimes, the "insert point" cursor in the Input Panel only blinks at half normal speed.

      Technical Note: The problem occurs when you have already evaluated one or more Scheme expressions, and have scrolled back to a previous command and started to modify it. When I first encountered the problem, the "insert-point" cursor would not blink at all in these circumstances. I have implemented a partial fix that restores blinking at half the normal rate, but I have not been able to do any better, so far.

  • Kittens Escaping from the Dock:

    At various times, the Macintosh operating system will hide the dock -- that is, the area of the main display that has a lot of application icons lined up in a row will slide out of sight for a while. If parallel instances of Wraith Scheme were running when that happened, the icons for the kittens may not be in the dock when it reappears. (As far as I can tell, the icon for the MomCat will always be present.)

    The kitten processes will still be running -- you will be able to find their Wraith Scheme windows and use them, as before. If you need to get to a particular kitten's Wraith Scheme window in a hurry, you can always make it pop up by using the "Bring Kitten To Front" menu item in the MomCat's Window Menu.

    Since this matter seems to be no more than a mild annoyance, I have not yet investigated it in detail. Maybe the kittens just sneaked off to play somewhere when no one was watching them.

Limitations:

  • Read and Print Overflow:

    Although Wraith Scheme can store large and complicated data structures in its main memory, it cannot necessarily read them in all at once: Wraith Scheme can read lists that are very long. In testing, I have loaded files whose text included lists of 100,000 items, something like:

      '(item-1 item-2 ... item-99999 item-100000)
      

    However, lists that are too deeply nested will cause Wraith Scheme to crash. Such a list might be

      '((( ... ((( some-list-item ))) ... )))
      

    in which the "..." stands for tens of thousands of parentheses of the appropriate kind

      Technical Note: The problem is stack overflow in the underlying routines, which are written in C. When the reader reads lists, it iterates in the "cdr" direction, but does recursive (and non-tail-iterative) calls in the "car" direction.

    There is a similar problem in the routines that print long or deeply-nested lists, but I have not tested to determine its extent.

  • Quitting When Garbage Collection Is Happening:

    Wraith Scheme will crash if a kitten exits while garbage collection is in progress. Therefore, if you try to quit from Wraith Scheme (via the "Quit" menu item and the like) while garbage collection is happening, Wraith Scheme will wait till it has finished before quitting. Normally, that is not a problem, but if you are using a large Scheme memory, it may take a long time before Wraith Scheme actually quits. Worse, if there should be some kind of failure during garbage collection (and that would be a serious bug -- let me know about it if it happens), it may be impossible to quit from Wraith Scheme by the usual means. In that case, remember that Apple provides a "Force Quit" command for every application, which you can find by holding down the "option" key while clicking on the application's icon in the dock.

  • Numerical Exactness:

    Wraith Scheme relies in part upon built-in features of MacOS and of Macintosh hardware to determine whether or not the result of a floating-point arithmetic calculation is exact; this term refers among other things to what the standard Scheme procedures "exact?" and "inexact?" return. These built-in features vary in capability from one version of MacOS to the next, and from one kind of Macintosh hardware to another. Briefly, on my 13-inch Macbook, which has an Intel processor, MacOS 10.5 (Leopard) does a slightly better job dealing with exactness than does MacOS 10.4 (Tiger), and both do a better job than does MacOS 10.4 on my old G3 iBook, which has a PowerPC processor.

    The main consequence here is that sometimes you might expect that a floating-point calculation would return an exact result, but the procedure "exact?" doesn't say that it did. Furthermore, what "exact?" has to say about the result of any given calculation may vary depending on what kind of Mac and which version of MacOS you are running.

    This mildly inconsistent behavior is not technically a Wraith Scheme bug, since the R5 standard is rather lenient about requiring Scheme implementations to return exact results whenever possible, but it bugs me, so I thought I would report it here.

  • Numerical Accuracy:

    The floating-point algorithms used by the Macintosh differ from one version of MacOS to the next and also from one kind of processor hardware to the next. Thus the numerical results returned by Wraith Scheme floating-point calculations may vary depending on which version of MacOS you are running and on what kind of Macintosh you have, even if you perform the same calculation, using the same input data, and with the same size of floating-point number (32-bit or 64-bit). The differences are typically very small -- down in the least significant digits of the result -- but they are there. The trigonometric and inverse-trigonometric routines are where I have most often noticed such differences.

Common Problems and Solutions:

Here are a few hints about problems that may happen when you try to run Wraith Scheme:

  • Wraith Scheme crashes as it is starting up, without getting far enough emit any messages of its own.

    Make sure you have met the system requirements for Wraith Scheme. If that doesn't help, you might want to try some of the steps listed in the "Elementary Debugging" section. Or you might just want to send me a bug report.

    Check the MacIntosh Console Log for error messages from Wraith Scheme: Wraith Scheme may put error messages there if it encounters a problem early in starting up, before Wraith Scheme's own error-reporting mechanism has gotten going. The console log is somewhere in the "Console" folder of the "Logs" folder of your computer's "Library" folder. On my Macintosh, the Unix path to the console log I look in is "/Library/Logs/Console/501/console.log". (The "Console" folder is organized so that there is one console file for each user who has an account on your Macintosh -- the "501" in the Unix path refers to the folder with the log for the user account I use on my own Macintosh when I am using Wraith Scheme.)

  • Wraith Scheme complains about insufficient memory.

    Try running Wraith Scheme with less memory requested. See the section, Changing the Startup Defaults.

  • Wraith Scheme takes forever to initialize.

    The likely cause of this problem is that Wraith Scheme is trying to initialize a large main memory, and that does take a while. As a rule of thumb, if the main memory size you have requested exceeds a quarter the size of the physical memory (RAM) installed in your Macintosh, initialization delays may be excessive. The main fix here is just to wait, though it may help if you shut down other applications.

    If you don't want to wait, you may force Wraith Scheme to quit via the special menu that appears when you option-click on the Wraith Scheme icon in the dock. If you want Wraith Scheme to forget about trying to use a large memory in the future, find the Wraith Scheme preferences file and delete it, and Wraith Scheme will create a new preferences file with default preferences the next time you start it up:

    The preferences file will be named "com.Jay_Reynolds_Freeman.WraithScheme.plist" (yes, it will have my name, not yours), and it will be located in the "Preferences" folder of the "Library" folder of your home folder.

      Technical Note: If you are willing to be bold, you may edit that preferences file by double-clicking on its icon: Once it is open, click on the small triangular icon near the word "Root", locate the "MainMemorySize" item, click on the number associated with it -- it is in Megabytes -- and change it to however many Megabytes of memory you want. If things get messed up, just delete the whole file.

    The reason you have to modify or delete the preferences file in this circumstance is that when Wraith Scheme is initializing memory, it hasn't yet gotten far enough in starting up so that you can just open the preferences window and change the memory size in a more normal way.

  • Wraith Scheme takes forever to garbage-collect.

    The likely problem is that Wraith Scheme is using a large main memory, in which garbage collection simply takes a long time.

    The speed of garbage collection will vary from fast -- when the Wraith Scheme main memories are contained entirely within physical memory chips -- to very slow -- when the Wraith Scheme main memories are in part stored as virtual memory, on disk. It takes a long time to "swap"; that is, to move data back and forth between disk and physical memory. On a 2006 model Macbook, with a 2 GHz Intel Core Duo processor and 1 GByte of memory, with no other user processes but Wraith Scheme running, with a Wraith Scheme main memory size of nearly 1 GByte, with a substantial portion of main memory containing non-garbage, I have seen garbage collection take as long as twenty minutes.

      Technical Note: Most of the swapping takes place early in the garbage-collection process, and I have no way to monitor the progress of swapping, so there isn't much point in using a progress indicator to show what is going on; it would just sit at a fixed position for a long time, then rapidly zoom through the rest of its range.

  • You try to type something in the main window, and nothing happens -- no text appears anywhere.

    Have you clicked in the Input Panel, to select that area for typing? The Input Panel is normally the only part of the Wraith Scheme window that will accept typing: If your last mouse click in the Wraith Scheme window was anywhere else, anything you type will be ignored.

    Input Panel

    The left end of the Input Panel, full size.

  • You get error messages suggesting that such basic primitives as "define", "if", "let", "cond" and "begin" are undefined.

    These basic primitives, as well as several others, are macros that are only available in the saved world that comes with Wraith Scheme, or in worlds that you have made from it. See the section, Wraith Scheme Startup Actions.

  • You aren't quite sure you know enough Lisp or Scheme to operate Wraith Scheme properly.

    See the Scheme References and Lisp References sections. In order from simplest to most complicated, I recommend (1) Friedman and Felleisen, (2) Springer and Friedman, and (3) Abelson, Sussman and Sussman. And do get a copy of the "R5" report: You will need it sooner or later.

    Or, try an Internet search.

    Don't forget the help files available via the Help Menu.

  • You are tired of seeing the demonstration program when Wraith Scheme starts running.

    Open the "Preferences" panel via the Wraith Scheme menu, clear out the text in the window after "Load This Source File After Startup", and press the "Accept These Preferences" button.

    Default Preferences Window

    The Preferences Window, full size, showing Wraith Scheme's default preferences.

  • The fonts are too small to read comfortably, particularly with that silly yellow background.

    Look in the Font Menu for commands to change font size, text color, and background color. And hey, I like the yellow background. But if you do not, there are many alternatives ...

    Colorful Window with Big Font


    Pastel Window with Small Font

    Font sizes and colors to suit every mood... (reduced size).



  • You can't figure out how to create programs and get them into Wraith Scheme.

    Use any programming editor, text editor, or word processor you like, to create a file containing your source code. Save it as a text document -- Scheme requires ASCII text. Use Wraith Scheme's "Load File" command (in the Interpreter Menu) to load the file, then do what you will with the things your file defines.

    If you are debugging code, Wraith Scheme has the commands "Load Last File", "Load Next-to-Last File", and "Load Recent..." (all in the Interpreter Menu, and there is a button for "Load Last File" in the Basic Buttons Drawer) to get at recent files quickly, without fussing with a browser or a long path name.

    There is also the "Load Last File When Updated" command in the Interpreter Menu (and there is a button). When you check this command, or push the button in, Wraith Scheme will look at the last file you have loaded every few seconds, to see whether you have updated it. If so, Wraith Scheme will reload the file automatically -- in essence, Wraith Scheme will push the "Load Last File" button for you, whenever you update the file. That way, you can make changes to the file using your favorite editor, save them, and have the newly-changed file loaded by Wraith Scheme automatically, so that your changes will be ready to test when you switch to the Wraith Scheme window.

    Letting Wraith Scheme load files this way allows you to create and edit Scheme source-code files using the editor you prefer, instead of using some built-in editor that I happened to like.

  • Compiling takes forever.

    Wraith Scheme's internal compiler is indeed fairly slow, and I have no present fix for that problem. Remember that you can turn the compiler off, via the "Compile Defines" menu item in the Interpreter Menu, or by means of procedures described in the State Flags section. Also, be advised that the compiler is much happier dealing with a large number of small procedures than with a small number of large ones.

  • You can't keep all these stupid parentheses balanced!

    Welcome to the club. Many programming editors have parenthesis-matching features; you might try the version of Emacs that comes with Apple's "Xcode" development environment -- it runs in a Terminal shell. As I write these words, Xcode is available free from Apple.

    Wraith Scheme itself will provide cues about missing parentheses and missing double-quotes when you are entering text directly into the Input Panel: Open the Basic Buttons Drawer, type an expression that doesn't have enough right parentheses -- something like

      (+ 2 2
      

    -- and then press "return". A little text panel will appear at the bottom of the Basic Buttons Drawer to remind you about the missing right parenthesis, like this:

    Expect Right Parenthsis

    For a missing quotation mark, the panel looks like this:

    Expect Quotation Mark

    That little text panel will stay visible even when you slide the Basic Buttons Drawer part way closed -- the text panel doesn't start to disappear until the drawer is almost closed.

Elementary Debugging:

If you encounter a problem while running Wraith Scheme, you might want to do a few things on your own before contacting me, both to save your time if the problem turns out not to be Wraith Scheme's fault, and to help me identify and fix any bug that may be present.

Try to pin down what it takes to make the problem happen, as accurately and completely as you can. Unreproducible bugs are almost impossible to fix. They are like the rattle in your car that goes away when you take it to a mechanic, or the things that go bump in the night but are not there when the sun rises.

Here are some things to do, that might help pin down a problem:

  • If the problem happened when you were running code that you had compiled, try again without compiling the code. That is, turn off the "Compile Defines" option, reload your code without applying "e::compile-form" to any of it, and try again. If the problem does not recur, or recurs in a different way, it may be that the difficulty is with the compiler itself.

  • Reboot your Macintosh and try again.

  • Reboot your Macintosh from a disc (in case of a virus) containing system software just as it came from Apple and try again.

  • Get a fresh copy of Wraith Scheme and try again.

  • Carefully consider the possibility of a computer virus or similar software abomination. There are no general rules to detect these: No two are alike. Magazine articles, Internet searches, user groups and dealers can help you learn about the latest viruses.

  • See if you can duplicate the problem on another Macintosh. If so, then you will know that your own computer's hardware and software are not at fault. Take care to prevent the spread of any virus that may be present in your own Macintosh.

If you do send me a bug report, give your best description of the problem and of what I must do to make it recur for investigation. State what kind of Macintosh you used, how much memory it had, what version of the Apple System Software you used, and whether you were using the compiler. If you suspect a problem with Wraith Scheme's interaction with some other software, tell me about that, too.

It will help me a lot if you do these things and describe what happened, and you may be able to save yourself some time if the problem turns out to be one you can fix.

I may not be able to do much about your bug, though, if I do not have the same kind of Macintosh and the same software that you do: If the problem turns out to have something to do with hardware or software that I do not have, I am unlikely to be able to reproduce it, much less fix it.

Development Testing:

This section describes the tests I perform before releasing a version of Wraith Scheme. I include it not to boast about how much testing I do, but to apologize for how little. I want you to be able to read this section if you encounter a problem, and learn immediately whether or not you are using Wraith Scheme in a way I have tested. Don't waste time trying to cope with problems I have had no opportunity to ferret out: Just send a bug report.

Wraith Scheme was originally developed on a 13-inch Macbook with a Gigabyte of memory and an 80-Gigabyte hard drive, running MacOS version 10.4.6 and later, but I have since acquired a Mac Pro running MacOS version 10.5 and now use that for development. I also have an an old G3 Mac that I use for testing Wraith Scheme on the PowerPC architecture.

I have a test suite comprising millions of Scheme S-expressions, which I run frequently. In general, the tests operate by calling either "load" or "e::set-input-port!" on various files, or by redirecting I/O via command-line options, and record output on transcript files, for subsequent comparison with files that contain correct output for the tests. My suite attempts to exercise each built-in function or macro of Wraith Scheme in at least a few interesting cases, to create every non-fatal error condition that Wraith Scheme can detect, and to perform many tests of Wraith Scheme's numeric input and output routines.

Prior to releasing Wraith Scheme, I run the test suite repeatedly, for a total of twenty-four hours or more of execution time, and verify that Wraith Scheme does not crash and continues to produce correct results.

Not all of the features of Wraith Scheme can be exercised by evaluating expressions: I use a list of manual operations to test Wraith Scheme Instrument Panel commands, Dialog Panel interactions, and so on.

None of this should impress you. I have worked professionally in software/hardware testing, where I have seen person-years of effort and machine-years of computer time spent on testing and debugging systems simpler than Wraith Scheme, without finding all the bugs. I have made only a small fraction of that effort testing Wraith Scheme.

Furthermore, I have little access to other computers for testing.

I would appreciate additional reports of successful use of Wraith Scheme on Macintosh configurations or types that I have had no opportunity to test. I will be particularly eager to hear of any bugs in Wraith Scheme that appear to relate to circumstances that I did not test.

Notwithstanding the formal test suite, probably the most important testing I do is to use Wraith Scheme myself. I have written lots of macros and a compiler in Wraith Scheme: They or the code they generate are part of the distributed world loads, and are exercised in even the simplest Wraith Scheme programs. I have used a checkbook-balancing written and run in Pixie Scheme to manage my own checkbook, and the bank hasn't come after me yet. (That program has been ported to Wraith Scheme, and is available via the "Scheme Source Code Examples" menu item of the Help Menu.) I have written or ported a modest amount of other software -- several thousand lines at least -- and it all seems to operate correctly. That's encouraging. But the ultimate test is not whether I find any more bugs in Wraith Scheme, but whether you do. Let me hear from you when you do; not "if you do" -- "when you do".

Timeline:

What's New:

This section summarizes what is new in Wraith Scheme since the previous release. I omit cosmetic improvements, minor changes in documentation and minor changes in displays.

Wraith Scheme's major development path is now as a 64-bit application, but I will support the 32-bit version of Wraith Scheme with bug fixes.

Items are listed in more or less the order in which I dealt with them.

The current release is 1.36, the twelfth release of the version of Wraith Scheme that is compiled as a 32-bit application.

  • Bug Fix: There was a bug that did not occur on all Macintoshes -- in particular, it did not occur on any of mine -- in which the Wraith Scheme Input Panel would scroll intermittently when the user was typing into it. The scroll would move the actual line of text being typed, including the text insertion point, one line down -- out of sight below the bottom of the Input Panel itself. I believe this one is fixed, but it is difficult to be completely certain without having a large variety of Macintoshes to use for testing.

What Used to be New:

This section summarizes changes in Wraith Scheme between its first release and the last one before what is now current. I omit cosmetic improvements, minor changes in documentation and minor changes in displays.

Items are listed in more or less the order in which I dealt with them.

Release 1.35 was the eleventh release of Wraith Scheme.

  • Bug Fix: The procedures "e::bit-shift-right-logical" produced incorrect values when shifting a quantity whose most significant bit was set. Fixed.

Release 1.34 was the tenth release of Wraith Scheme.

  • Bug Fix: The procedures "e::show-locks" and "c::release-locks" produced large amounts of spurious output. Fixed.

  • Bug Fix: A saved world could not successfully be loaded when fewer kittens were in use than when it was saved; the first garbage collection after the load encountered a fatal error. Fixed.

  • Bug Fix: Trying to select all of the text in the Wraith Scheme Input Panel did not always work. Fixed.

  • Changed the "Trim Scrollback" command and menu items so that they reduce the amount of scrollable text by half, or to 6000 characters, whichever is greater. The previous value was 20000 characters.

  • Added new procedures "c::disable-window-output", "c::enable-window-output", and "c::window-output-enabled?". See Top-Level Control.

  • Added new procedure "c::kitten-reset". See Keeping Track of Things.

Release 1.33 was the ninth release of Wraith Scheme.

  • Added as an enhancement, a procedure to tell when main store is ninety percent full. See Storage Management.

  • Bug Fix: Wraith Scheme failed to report an error when attempting to read an unquoted empty list, and unnecessarily reported a fatal error -- instead of a recoverable error -- when attempting to evaluate one.

  • Added as enhancements, procedures c::kitten-input-queue, c::kitten-empty-queue? and c::kitten-purge-queue, for debugging and gathering information about the queues used for interprocess communication between Wraith Scheme kittens. See Interprocess Communication.

  • Achieved modest speed increase -- perhaps a factor of two -- in some circumstances.

  • Achieved modest reduction in consing -- perhaps a factor of two -- in some circumstances.

  • Enhanced the garbage collector to be aware of locality of data use when repopulating Scheme main memory, in an attempt to make Wraith Scheme at least minimally NUMA-aware when NUMA computers become common. (NUMA is short for "Non-Uniform Memory-Access".)

Release 1.32 was the eighth release of Wraith Scheme. Things new in it included:

  • Bug Fixes: I have done a major rewrite of the low-level locking mechanisms which prevent simultaneous actions by separate Wraith Scheme kittens from corrupting Wraith Scheme's shared main Scheme memory.

    The war story here is, that I had done previous testing of the parallel implementation of Wraith Scheme on a Macbook 13, that only had two processor cores and in fact ran relatively little code in parallel -- it mostly swapped. In late January, 2008, I bought a high-end Mac Pro, with eight cores; it was more than capable of running several Wraith Scheme processes in parallel, and "shook the tree" sufficiently hard thereby, to expose a handful of bugs that had escaped earlier testing.

    They were tough bugs, involving communications and locking between multiple asynchronous processes, and in general never repeated themselves the same way twice. It took three months to get things back to stable. I don't ever want to do that again, but I fear that I shall have to.

Release 1.31 was the seventh release of Wraith Scheme. Things new in it included:

  • Bug Fix: When Apple Security Update 2007-009 was installed in Macintoshes with Intel Processors, Wraith Scheme 1.30 lost its ability to perform "paste" and "drag-and-drop" operations in its "MomCat" window. The present release restores that capability. As I released Wraith Scheme 1.30, in late January 2008, it was not clear whether or not Apple would release some form of update that will restore full functionality to Wraith Scheme 1.30; however, Apple had been most concerned and most responsive to my bug report and request for technical assistance with the problem.

  • Bug Fix: An unguarded critical section involving the input queues whereby one parallel Wraith Scheme process can request another to do something, allowed "e::tell-kitten" to fail when the kitten being "told" had only one item in its input queue and was in the process of dequeuing it.

  • Bug Fix: The mechanism to load the last file when updated only worked for the MomCat.

Release 1.30 was the sixth release of Wraith Scheme. Things new in it included:

  • Bug Fix: Procedure "e::set-current-directory!" returned the string that was its argument, not what it was supposed to, which is #t.

  • Bug Fix: Both set-car! and set-cdr! incorrectly reported an error when their first argument -- the pair being altered -- had a car that was constant. That is, previously:

      (set-car! (list '(1 2 3)) <object>)  ;;  ==> <error message>
      
      (set-cdr! (list '(1 2 3)) <object>)  ;;  ==> <error message>
      

    Both of these error messages were incorrect: Both operations should have worked, and now do.

  • Bug Fix: The procedure "load" did not maintain the value of the current input port.

  • Bug Fix: The compiler incorrectly handled permanent symbols whose values were certain types of Scheme objects. (It worked fine for permanent symbols whose values were procedures, which is the most useful case.)

  • Numerous internal changes: The polite term is "code refactoring". Less polite terms have been reported.

  • Slight enhancements to the efficiency with which the garbage collector compacts non-garbage for reuse.

  • Trivial enhancements for logic programming: The addition of logic-programming capability to Wraith Scheme is a work in progress, and in the release for which this comment is prepared, very little progress has been made.

  • Major enhancements for parallel processing.

Release 1.21 was the fifth release of Wraith Scheme. Things new in it included:

  • Bug Fix: Procedures displaying and writing strings worked incorrectly when the strings contained percent signs ('%').

      Technical Note: C programmers can probably figure out what caused the problem ...

  • Bug Fix: Wraith Scheme allows numeric constants to be written as fractions -- such as 22/7 -- but has no means to store numerator and denominator separately; instead, it performs the division and returns the result. Previously, the result returned was reported as inexact, even when the division could be carried out with no loss of precision. I have been able to refine that report, but only on Macintoshes, such as the Macbook series, that use Intel processors.

    On Macintoshes that use Intel processors, Wraith Scheme now returns an exact result when the result of the division is exact. For example:

      1/2  ;;  ==> #e0.5  ;;  Exact.
      

    but of course

      1/3  ;;  ==> 0.33333333333333331  ;;  Inexact.
      

    On Macintoshes that use PowerPC processors, Wraith Scheme still returns an inexact result even if the result of the division is exact. For example:

      1/2  ;;  ==> 0.5  ;;  Inexact.
      

    and of course

      1/3  ;;  ==> 0.33333333333333331  ;;  Inexact.
      

    The philosophy here is that Wraith Scheme will report numbers as inexact unless it can prove that they are exact.

      Technical Note: For some reason, I cannot get the floating-point exception mechanism to work on the old G3 Mac that I use to make sure Wraith Scheme works on both Intel and PowerPC architectures. I do not have access to a G4 or G5 Mac for further investigation.

  • Bug Fix: Fixed a problem with the hygienic macro implementation that was causing failure of "do" statements in which not all declared local variables were automatically recalculated each time through the loop. That is, "do" statements such as

      (do ((i 0))
          ((= i 3) #t)
          (display i)
          (newline)
          (set! i (+ i 1)))
      

    did not work, whereas the seemingly-equivalent

      (do ((i 0 (+ i 1)))
          ((= i 3) #t)
          (display i)
          (newline))
      

    worked just fine. Now, both work.

  • Added as enhancements, several procedures to aid in formatting numbers.

  • Added as an enhancement, a procedure to test or demonstrate Wraith Scheme's fatal-error reporting mechanism. See the last entry in the section on Top-Level Control.

  • Added as enhancements, procedures to examine and modify the internal flags used to determine whether Wraith Scheme compiles defines automatically and whether Wraith Scheme displays numbers with the full precision available. See the section on State Flags.

  • Added many images to the Wraith Scheme Help File. The substantial increase in application size that occurred with this release is almost entirely due to these images.

  • Added a menu item to the Font Menu to allow choice of the text color that Wraith Scheme uses.

  • Added a "Preferences" item to specify text color.

Release 1.20 was the fourth release of Wraith Scheme. Things new in it included:

  • Wraith Scheme became an "R5" Scheme implementation.

  • Modest compiler enhancements.

  • Added an Interpreter Menu menu item to disable output to the main window; such output is slow, so this feature may allow your programs to run faster.

Release 1.11 was the third release of Wraith Scheme. Things new in it included:

  • Bug Fix: The hygienic macros implementation had some problems, most of which evidently stemmed from me misreading the specification.

  • Modest compiler enhancements.

  • All the files that used to be provided separately, as supplements to the distribution, were contained within the application itself, accessible via the Help Menu.

Release 1.10 was the second release of Wraith Scheme. Things new in it included:

  • Bug Fix: Fixed a significant bug that affected both cut-and-paste into the Input Panel and drag-and-drop into Input Panel: Performing either of these operations with more than one line of text at a time caused Wraith Scheme to hang; that is, the multicolored spinning cursor appeared and the program accepted no further input.

  • Bug Fix: The "Trim Scrollback" command did not work quite as documented -- it was always trimming the scrollback so that at most 20000 characters remained, instead of cutting it by half to a minimum of 20000 characters. Fixed.

  • Bug Fix: The "Load Last File When Updated" feature did not deal correctly with an unsuccessful load; that is, one that produced an error. In that such cases, it would keep trying to reload the same file over and over again, getting the same error message each time. Fixed.

  • Bug Fix: There used to be some glitchiness in scrolling of the Wraith Scheme Main Display Panel; when you typed blank lines in the Input Panel, the main display panel would alternate between scrolling two lines and not scrolling at all.

  • Increased the largest available font size for the Wraith Scheme Window to 36-point.

  • Additional help file and Help Menu command: The new file is a dictionary of Wraith Scheme commands and terminology.

  • Procedure "e::error-port", to retrieve the port where Wraith Scheme prints error messages.

  • "Load Recent..." menu item, to allow easy reloading of recently-loaded files.

  • "Load Next-to-Last File" menu item, to reload the next-to-the-last file loaded.

  • "Change Background Color..." menu item, to change the background color of Wraith Scheme text areas.

  • "Preferences" item to specify background color for Wraith Scheme text areas.

  • Initialization with large amounts of memory is vastly faster.

  • Garbage collection with large amounts of memory is notably faster.

Release 1.00 was the first release of Wraith Scheme; it was all new.

What Might be New in the Future:

Besides fixing bugs and making internal improvements, my wish list for the future of Wraith Scheme includes the following items, which are not necessarily in the order in which I might get around to doing them:

  • Further development of the 64-bit version of Wraith Scheme, which as I write these words in November, 2009, has been released as Wraith Scheme 2.00. (Wraith Scheme 2.00 requires a Macintosh using an Intel Processor and running at least MacOS 10.6 ("Snow Leopard").)

The future probably does not hold:

  • More updates of Wraith Scheme that run on MacOS 10.4 (Tiger), except for major bug fixes.

  • More updates of Wraith Scheme that run on PowerPC processors, except for major bug fixes.

      Technical Note: It would certainly be possible to create a 64-bit version of Wraith Scheme that ran on PowerPC processors; the problem is that the only PowerPCs that can run 64-bit applications are G5s: I myself do not own a G5 Macintosh, and therefore I could not test such a version of Wraith Scheme on the PowerPC. Moreover, there are some big-endian/little-endian things related to Wraith Scheme world files that would definitely require testing. I hope all understand that I am unwilling to release new features that I cannot test.

Miscellaneous Information:

Numbers Revisited:

Many people think the different kinds of numbers are separate, so that no number can be of more than one kind. They think that integers and reals are different kinds of numbers, so that no integer can be real, and so on.

That's false. They overlap. Specifically, every integer is also rational, real and complex; every rational is real and complex; every real is complex; and they're all numbers.

For example, 1 is an integer. It is also a rational (being equal to the quotient of two integers, namely 1/1, or 2/2, or...), it is on the real line, and it is also in the complex plane -- we could write it as 1 + 0i. Typographic choices, such as the inclusion of a decimal point, an exponent, or trailing zeros, do not alter the mathematics. Thus "1", "1.", "1.0", "1.0e0" and "1.000000000000000" are all ways to write the same mathematical number; namely, the integer "one".

Some wag once said, "A computer scientist is a person who refuses to believe that 1.0 is an integer." Don't you make that mistake.

Much of this confusion is because many computer languages use different kinds of machine storage for numbers given with a decimal point than for numbers given without one. A language might store "1.0" as an IEEE 64-bit floating-point number, yet store "1" as a 32-bit word with just the least-significant bit turned on. It is the integer "one" in either case. Some people think floating-point numbers cannot be integers. That's wrong. What counts is the value, not how it's stored.

If you want to know how Wraith Scheme is storing a particular number, there are some special predicates you can use to find out.

More confusion stems from the fact that typographic conventions are widely used to convey information about the precision of a number that is imperfectly known. Thus in science or engineering, use of the string "1.000" to represent a number often means "the number I am talking about is between 0.9995 and 1.0005, but I don't know for sure what it is, so I will use the representative exact value 1 to stand in its place." This convention obscures the mathematics of numeric types: Thus in the example given, the integer 1 might actually be standing for the integer 1, for the rational number 10001/10000, for the irrational number (1 + pi/10000), or for the complex number (1 + i * pi/10000).

The built-in features of Scheme are in any case not powerful enough to support such conventions: You can specify that a number is exact or inexact by means of the "#e" and "#i" prefixes, but Scheme records only that one bit of information. There is no built-in means to tell Scheme how many digits of precision the number has. As far as input to Scheme is concerned, the strings "1.50000" and "1.5" indicate the same number and the same status of the "exact bit". (In the case of Wraith Scheme, that number is the inexact rational 1.5.)

Just for fun, ask yourself (A) Which of the following numbers are complex? (B) Which are real? (C) Rational? (D) Integer?

    42
    1.
    -2.000000
    345.62e2
    9.6149604775e23
    

    (Hint: Does 9.6149604775e23 have a fractional part?)

Answers: (A) All of them. (B) All of them. (C) All of them. (D) All of them.

Technical Details About Wraith Scheme:

Where do I start ...

  • Wraith Scheme is a descendant of Pixie Scheme, which I wrote for mid-to-late-1980s versions of the Macintosh. Much of Wraith Scheme's technical minutiae stem directly from Pixie Scheme, but for clarity (hah!) I will not always distinguish between Wraith Scheme and Pixie Scheme in this section.

  • Pixie Scheme was written in C, specifically in Macintosh Programmer's Workshop (MPW) C versions up through 2.0.2. I developed it on a plain vanilla Macintosh II with 1 MByte of memory -- no typo, that's "M" for "mega". It ran fine in one megabyte, and still does, for that matter. I later bought some more memory, and ported Pixie Scheme to later versions of MPW C -- the last was 3.2b3.

  • Many failings or biases in the first release of the program no doubt reflected the specific nature of my environment. For example, 1 MByte wasn't enough memory to test Pixie Scheme adequately under MultiFinder. For example, Apple didn't get around to releasing an MPW C compiler that generated correct 32-bit code until after I had shelved the Pixie Scheme project. (That last was very frustrating. My early Mac II was not a full 32-bit machine in any case; it had an Apple memory-management unit that handled only 24-bit addresses, so the program worked fine for me. Yet I would get bug reports from folks using 32-bit machines that I couldn't so much as duplicate, much less fix. I didn't even know anyone with a 32-bit Macintosh at the time.)

  • More recently, I ported Pixie Scheme to run in a Unix (Terminal Application) window in MacOS X on my Macbook, using the GNU C compiler. That was enough of a change to warrant changing the name of the program, to Wraith Scheme. First I made it run using only the simplest kind of terminal input and output -- the kind of thing that would work on a teletype. Then I got a version going that used the Unix "ncurses" package for terminal output.

    The experience of excising the essence of Pixie Scheme from an old-style Macintosh application, and getting it going under Unix with two quite different styles of I/O, gave me a chance carefully to encapsulate the code for a functioning Scheme interpreter separately from the code that let that interpreter communicate with the outside world. I had actually planned it that way -- even when I was writing Pixie Scheme, I anticipated that maybe, some day, it would run in a different I/O environment, and therefore I tried to perform the encapsulation at that time. I was setting up for what is now called the "model-view-controller" pattern of software design and implementation, though I am not sure that the term existed then.

    From there, it was straightforward -- I won't say easy -- to wrap a more modern Macintosh-style user interface around the Scheme interpreter. It took about a month of serious effort to get Wraith Scheme going as a Macintosh application. The Macintosh wrapper is a "Cocoa" application involving not quite three thousand lines of Objective C and a set of interface classes (".nib" file stuff) built in Apple's Xcode development environment.

  • Wraith Scheme is a tagged-object Lisp. Each object comprises a 32-bit tag and a 32-bit entity that is either an immediate datum or a pointer. The precise nature of the object is indicated by the tag, which has seven bits of type information, two bits for cdr-coding, two for the garbage collector, and lots more for miscellaneous internal purposes. I do not document the tag bits because the tagging scheme is likely to change in the future.

  • Pixie Scheme began life as an SECD machine, but soon changed. The present Wraith Scheme implementation stores information equivalent to the contents of the D register on the stack, and uses a stack and a continuation which are separate data structures, not heap objects. It makes copies of the entire stack and of the entire continuation, in the heap, when necessary; for instance, when "call-with-current-continuation" is called.

  • The virtual machine that describes the implementation includes about a dozen registers. There is a stack pointer, which refers to a stack that is implemented as a data structure separate from the heap. There is a pointer to a list of environments. That entire list is a heap object. A continuation register points to a separate data structure that represents a list of instructions next to be executed; it is essentially the C register of an SECD machine. There is a register for returning tagged-pointer values from functions, a register for the top-level environment, several registers for ports in use, and a couple of scratch or special-purpose registers.

  • I have touched on the structure of Wraith Scheme's environment list while discussing the debugger, and will not repeat myself here. What gets put on the stack is too complicated and too subject to change to discuss.

  • Almost all text Wraith Scheme prints out, including most error messages and function names, is stored internally in large arrays of text strings. They used to be Macintosh resources when I was building Pixie Scheme with the old Mac ToolBox. Thus it should be relatively easy for an experienced C programmer, who has access to the source files for the Wraith Scheme program, to create custom versions of Wraith Scheme, or to port the program to another (human) language. I have not tried to do so myself, so I have undoubtedly forgotten to make it easy to alter some things that would need to be changed, but I suspect that what I have done would be helpful in such a project. If anyone is interested in such a port, contact me.

  • Wraith Scheme is written in a strongly object-oriented fashion. (If there had been a decent C++ or similar object-oriented variant on a C compiler available for the Macintosh at the time I started writing Pixie Scheme, I certainly would have used it.) There is lots of data encapsulation. There are many objects (structs) which contain (pointers to) functions which perform various operations, whose details differ from object to object. Thus I have a generic method for printing objects, which contains no "switch" statement: It merely looks up the "print" method for the object itself. In consequence, for a C program, Wraith Scheme is remarkably easy to modify and maintain. For example, it took only a few hours to add support for IEEE 80-bit floating-point numbers to Pixie Scheme, and most of that time was spent writing functions that actually implement operations on these entities, not in tying 80-bit floats into the control-flow structure of the program.

  • The stand-alone Macintosh version of Wraith Scheme is threaded: One thread runs the C code that does the work of the Scheme interpreter; it is the "model", in the model-view-controller design pattern. The controller and view use at least two more threads (I am never quite sure how many threads the operating system adds to the application).

    The view is an interface built using Apple's Interface Builder application, together with code for a couple of supporting controllers for specific parts of the view.

    The main controller -- the one that sits between the model and the view -- has two parts. The first part comprises a fair number of semi-autonomous methods whose actions are triggered by various events, such as typing "return" in the Input Panel or operating one of Wraith Scheme's buttons or menu items. The second part is a timing mechanism, that polls the evaluator thread regularly, to see if it has anything for the controller to do.

    The controller and model communicate via two one-way critical sections -- one for data flow in each direction -- with critical-section access controlled by pthread locking mechanisms. (And if critical-section access control were all there were to getting communicating entities to cooperate, my life would be much simpler.)

Scheme References:

These items are all from my bookshelves or download directories. Many have more recent editions.

  • Harold Abelson, Gerald Jay Sussman and Julie Sussman, Structure and Interpretation of Computer Programs, MIT Press, 1985. This is an introductory book on computer science for very bright college students. It both teaches and uses an earlier version of Scheme than that described in the R3 report, but the differences are minor. It features many excellent examples of programming in Lisp in general and in Scheme in particular. The early sections are a good introduction to the language, the later ones show well just how powerful it is.

  • William Clinger, "The Semantics of Scheme", in Byte 13, no. 2, 221-227 (February 1988). One of several introductory articles on Lisp-class languages in this issue of Byte.

  • William Clinger and Jonathan A. Rees (editors), "The revised 4 report on the algorithmic language Scheme", Lisp Pointers 4(3), ACM, 1991. The RN reports (N = 3, 4, 5 ...) define Scheme. They are manuals, not tutorials -- readable once you have some background in any Lisp, and invaluable for specific details, but likely to intimidate a beginner. I strongly recommend that you get copies anyway.

  • R. Kent Dybvig, The Scheme Programming Language, Prentice-Hall, 1987, and subsequent editions: The third edition is MIT Press, 2003. An outstanding work describing Scheme.

  • Daniel P. Friedman, William E. Byrd and Oleg Kiselyov, The Reasoned Schemer, MIT Press, 2005. Scheme integrated with logic programming.

  • Daniel P. Friedman and Matthias Felleisen, The Little Lisper, MIT Press, 1974, 1986, 1987, and subsequent revisions. An introductory book on programming in a style appropriate to Lisp, as a programmed text. The more recent editions use a dialect of Scheme as the language in which the examples and discussion are presented.

  • Richard Kelsey, William Clinger and Jonathan Rees (editors), 20 February 1998. "Revised5 report on the Algorithmic Language Scheme". Available on several Internet sites, such as http://www.schemers.org.

  • Jonathan Rees, "The Scheme of Things: The June Meeting", Lisp Pointers V(4) (October-December 1992).

  • J. Rees and W. Clinger (editors), "Revised3 Report on the Algorithmic Language Scheme", ACM SIGPLAN Notices 21, no. 12, 37-79 (December 1986); also an MIT Technical Report.

  • George Springer and Daniel P. Friedman, Scheme and the Art of Programming, McGraw-Hill, 1989. A good introduction to programming and to Scheme. More elementary than Ableson, Sussman and Sussman.

Lisp References:

These items are all from my bookshelves. Many have more recent editions.

  • Harold Abelson and Gerald Jay Sussman, "Lisp: A Language for Stratified Design", in Byte (magazine) 13, no. 2, 207-218 (February 1988). One of several introductory articles on Lisp-class languages in this issue of Byte.

  • John Allen, Anatomy of Lisp, McGraw-Hill, 1978. An oldie but a goodie. This rather advanced text describes Lisp mechanisms and data structures in considerable detail, with attention both to theory and to practice. Not for the faint of heart.

  • Eugene Charniak, Christopher K. Riesbeck and Drew V. McDermott, Artificial Intelligence Programming, Lawrence Erlbaum Associates, Publishers, 1980. An oldie but a goodie. The first section is titled "Advanced Lisp Programming", but after that it gets harder.

  • Peter Henderson, Functional Programming Application and Implementation, Prentice-Hall, 1980. An outstanding book on the theory, design and implementation of a class of Lisp-like functional programming languages. Wraith Scheme was originally based on the implementation of an SECD machine described herein. I found the book to be somewhat a "sleeper": I almost stopped reading it because the material in the first few chapters seemed elementary and familiar. I am glad I continued.

  • Samuel N. Kamin, Programming Languages: An Interpreter-Based Approach, Addison-Wesley, 1990. How to implement any language you like as long as it's Lisp. Well, not really: This book gives miniature, subset implementations of a representative selection of modern programming languages, all of whose syntaxes have been modified to be Lisp-like (prefix notation with lots of parentheses). The common syntax highlights the differences in semantics. The languages covered include a rather standard simple Lisp as well as simple subset of Scheme.

  • Guy L. Steele Jr., Common Lisp, Digital Press, 1984. The definitive guide to that dialect of Lisp which has the greatest claim to being a standard. As a manual, the book is excellent, but it is neither a tutorial nor an introduction. There is a revision (1990), even thicker than the original, that goes into more detail on such special features as the Common Lisp Object-Oriented Programming System.

  • David S. Touretzky, "How Lisp Has Changed", in Byte (magazine) 13, no 2, 229-234 (February 1988). One of several introductory articles on Lisp-class languages in this issue of Byte.

  • Patrick Henry Winston and Berthold Klaus Paul Horn, Lisp, Addison-Wesley, 1981 (and subsequent editions, later). This rather venerable tome is still a good introduction to Lisp and to what you can do with the language. The first edition uses the "MACLisp" dialect, which is no longer widely used (unless you have in your garage a DEC-20 mainframe or a Symbolics 36XX with down-rev software), but I believe that subsequent editions use Common Lisp. I learned Lisp with this book and a DEC-20. No, not in my garage. (Though I do have a friend who used to have a DEC-20 in her garage.)

Other References:

  • Douglas R. Hofstadter, Goedel, Escher, Bach, Basic Books, 1979. A thoughtful and deep book that deals (among other things) with some interesting and profound concepts that are part of computer science, and with other interesting and profound concepts that would be part of computer science if anyone could figure out how to work them in.

  • Tracy Kidder, The Soul of a New Machine, Little, Brown and Company, 1981. Everyone contemplating a career in the computer industry should read this book, the better to recognize job offers from places like this. What you do when you do get such an offer is up to you: I recommend you accept. But remember, misery loves company.

  • Dr. Seuss, On Beyond Zebra, Random House, 1955. As this classic children's book so clearly demonstrates, a language should allow you to express not only things you can think of, but also things you could not possibly have thought of if you hadn't learned it.

  • Guy Steele, The Hacker's Dictionary, Harper and Row, 1983. A funny and quite accurate guide to the jargon of the best of the best of computer scientists. This dialect is to programmers what Chuck Yeager's drawl is to test pilots. I thought the book was a joke until I joined an artificial intelligence lab and found everybody really did talk that way. In this context, incidentally, "hacker" has a much broader and more respectable meaning than its popular use as a synonym for "computer criminal". Virus weenies and digital peeping Toms do not deserve so honorable a label.

  • Edward R. Tufte, The Visual Display of Quantitative Information, Graphics Press, 1983; and Envisioning Information, Graphics Press, 1990. These books are the main reason I laugh uproariously whenever anyone tells me that some computer or program has decent graphics or a decent user interface. Few books on computer graphics or computer interfaces mention any of Tufte's works; perhaps the authors are too embarrassed.

  • David Michael Ungar, The Design and Evaluation of a High Performance Smalltalk System, MIT Press, 1987. If you read the table of contents and the back cover casually, you might think that this book is about implementing Smalltalk on a chip. Actually, the lion's share of the text deals with good and better garbage collection algorithms.

Whimsy:

On Dialectic and History:

Letter to the editors of "The California Tech", California Institute of Technology, Pasadena, California:

    Dear Editors:

            This June it will be twenty years since I graduated from CalTech. The anniversary has made me think: Possibly my thoughts may be relevant to the present student body.

            After CalTech I went to graduate school at the University of California's Berkeley campus. It was like going from a monastery to a madhouse. From the late sixties through the mid seventies, Berkeley was a tumultuous place, full of people who were bound and determined to change the world. What's more, each of them seemed to have a different idea of how to go about it. I could scarcely pass through the campus gates without being accosted by handbill-distributors from every imaginable kind of political, social and economic action group, all bent on modifying civilization to suit themselves. There were libertarians and communists, republicans and democrats, churches both bizarre and familiar, ecological advocates, draft resisters and military recruiters. The campus seemed overflowing with charismatic, impressive leaders, each with a separate agenda for social change.

            Often there were demonstrations: I rapidly learned to cut through the back alleys to get to class. Sometimes there was real violence: Once I walked out of the student cafeteria after lunch, only to find a National Guard helicopter spraying the plaza with riot-control gas. I decided I had better go back inside and have dessert.

            I was too bewildered to have anything to do with all this. I gravitated toward a small, ever-changing circle of science buffs and technology enthusiasts, people much like myself. We had no charisma and impressed no one. We would go out for pizza and talk. The discussion topics changed as our informal membership varied -- many liked space exploration, one was enthusiastic about computers, and so forth. If pressed, most of us would cautiously admit to some faith that scientific and technical developments were also important agents of social change, but in the midst of widespread turmoil of a different kind, I found such a belief ever less tenable. As the years passed, it seemed increasingly that the things I was interested in could scarcely matter in comparison to those other, more powerful forces.

            Yet in retrospect, it is remarkable how little came from the social and political movements of that time and place. I no longer remember the names of any of the Berkeley people who were out to change the world. I scarcely recall what they wanted to do. After a decade or two I must look hard to find our planet any different for their efforts. It seems that in the long run, they mattered all but naught.

            To my embarrassment, I have even forgotten most of the people in our group of pizza-eaters. Only recently did someone remind me of the name of the fellow who came to a few meetings and talked with such zeal about the prospect of small computers and their likely capabilities.

            His name was Steve Wozniak.

            Keep the faith.

                                                                    Jay Reynolds Freeman

                                                                    BS (Physics) '68
                                                                    May 1, 1988

Excuses:

The following excuses may help explain flaws or omissions in Wraith Scheme:

  • I do not possess your level of wisdom, insight or experience.

  • My computers include a Mac Pro, a Macbook 13, and a G3 iBook; I did not test Wraith Scheme extensively on other kinds of Macintosh.

  • I didn't think of that.

  • I was interested in writing a Lisp system, not a (choose one or more)

    • text editor.

    • ToolBox interface.

    • whizzy graphics package.

    • ...

  • I forgot.
  • I did not test Wraith Scheme under older versions of Apple's system software.

  • I didn't know how.

  • I thought I knew how, but I was wrong.

  • I did it the the way the R5 report says it should be done.

  • I did it my way.

Infrequently Asked Questions:

  • "Why would a sane person want to write a Lisp system?"

    < long, long pause ... >

  • "Well, why did you want to write a Lisp system?"

    To begin with, I know of no programming language better than Lisp for building large programs rapidly. Furthermore, I am interested in various technical details of implementing Lisp, in possible future Lisps and Lisp-like languages, and in blazing fast compilers.

    Given my fondness for Lisp programming, obviously I wanted a Lisp system around. Given my interest in internal details, developments and modifications, obviously I needed a system with source code, and I needed to be thoroughly familiar with that code. There were (and still are) several Lisps available with source, but the best means I know to become familiar with all the details of a large piece of code is to write it.

  • "Why Scheme?"

    Scheme is a small modern Lisp, well in the forefront of research in Lisp-like languages, whose nature allows it easily to be compiled.

  • "Why not Common Lisp?"

    Common Lisp is much larger than Scheme, in the sense of lines of code and time required to write them. Furthermore, in my opinion, Common Lisp is not nearly as elegant as Scheme.

  • "Why the name 'Wraith Scheme'?"

    I had cat named "Wraith" whom I dearly loved.

  • "Why name a program after a cat?"

    It makes as much sense as naming a computer after a raincoat. (Mee-yow!!)

    For the record, evidently Jeff Raskin deliberately misspelled "McIntosh" when he named Apple's new "computer for the rest of us". But so what -- it's still named after a raincoat!

  • "Why are you so fond of cats, anyway?"

    To those who understand, no explanation is necessary; to those who do not understand, no explanation is possible. Besides, they remind me that love can be unconditional, that innocence is worth protecting, and that curious optimism may discover a solution when greater minds would give up in despair.

  • "What's with all the weird humor and obscure references in this document, and with the occasional whimsical behavior of Wraith Scheme?"

    If you can't make it insanely great, at least make it greatly insane. Besides, where else would I find a captive audience for my jokes?

  • "What can we expect in future versions?"

    Who said anything about future versions? Oh, excuse me, I did. Well, there's an old Russian proverb: "Hope for the best, and expect the worst; thus you shall never be disappointed." What you should expect is very little, perhaps not even bug fixes if I get busy or distracted. One might hope for a faster and better compiler, more speed in general, a more powerful interface to the file system, a better debugger, and access to a small selection of whizzy Macintosh special features. I doubt there will be a better editor, a graphics package, or anything like a complete ToolBox interface. If I can figure out an elegant way to put in a foreign-function interface, I may add one.

  • "How am I supposed to write, edit and enter Scheme source code?"

    Use a text editor, and load the file. I use EMacs, but many others would do as well. On a Macintosh, cut-and-past and drag-and-drop work very well for moving small bits of text into or out of the Wraith Scheme window, as do the various buttons and menu items for loading recent files and for loading files when updated.

    Note that the "Load Last File When Updated" menu item of the Interpreter Menu, and the "When Updated" button in the Basic Buttons drawer, provide a way to load a file whenever it is updated. Thus you may use whatever editor you like to work on a file, and have Wraith Scheme load it for you automatically, as soon as you save your changes.

  • "Why not release source for Wraith Scheme?"

    Portions embarrass me: How many cooks -- even good cooks -- want people to see what their kitchen looks like? (For me, cooking is not so much an art as a survival skill -- how to stay alive in the kitchen.) Besides, who am I to deprive you of the chance to write your own 30,000-line program ...

  • "Do you think Wraith Scheme will ever turn into a commercial product?"

    For any chance of commercial success, I would have to do a compiler with a decent native-code code generator. Otherwise, the system's speed will not be competitive. I'm not sure I want to bother; I am interested in other aspects of compilation.

    Besides, I do not sense that the world is waiting with bated breath for yet another artificial-intelligence programming-language implementation just now. (Too bad -- I know a lot of people who could use some more intelligence, artificial or otherwise, perhaps most notably me ...)

  • "Could you tell us a little about the development history of Wraith Scheme?"

    Wraith Scheme is a direct descendant of "Pixie Scheme", which I developed in the late 1980s and early 1990s. Pixie was another cat. Pixie Scheme ran on Apple Macintoshes of that vintage, was available as shareware -- I asked for a shareware donation of one dollar -- and was actually used here and there. I shelved the Pixie Scheme project in 1991, because it had grown to the point where it was pushing on the limits of my original-model Mac II and of my development software. In 2006, I finally got a new Macintosh, and decided to do a port of Pixie Scheme to run in a Unix terminal shell on my Macbook under MacOS X. First I got it to run using the GNU C compiler, then subsequently the GNU C++ compiler, then I wrapped a contemporary Macintosh interface around it. Those changes seemed enough to warrant a new name; hence "Wraith Scheme".

    My "Wraith Scheme" files include some thirty-five thousand lines of C and Scheme source code, and close to a million lines of test programs and expected answers to those tests. It took two or three thousand hours to create Wraith Scheme, in isolated intense bursts spread over the five years 1987-1991, and in the period from late 2006 to date. I am a moderately experienced C and Lisp programmer (I have probably written over 250000 lines of the former, including C++, and 75000 lines of the latter), but Pixie/Wraith Scheme is by far my most complicated program ever.

    Pixie Scheme was my first stand-alone Macintosh application. (I must have learned something: It took less than twenty minutes to write the second one.) As Macintosh applications go, Pixie/Wraith Scheme is a little weird: For example, it sort of does not have a main event loop. (Pixie Scheme really didn't have one; Wraith Scheme uses one for the user interface, but not for the Scheme interpreter itself.)

    The greatest single break I had in this project was that I did not have access to a personal computer when I started working on Pixie Scheme: I spent over six months in design and analysis without writing a single line of code. I am certain that without so spending this time, I would not now be nearly as far along with Wraith Scheme as I am, and I strongly suspect that I would have given up on Pixie Scheme in the first place.

    In developing Pixie Scheme, I missed a utility like Unix's "lint". I missed a C compiler that accepted function prototypes. I missed a lot of sleep. I missed a source-level debugger. I used MacsBug now and then. The combination of Apple's Xcode development environment and GNU tools that I use for Wraith Scheme, is a whole lot better than what Apple provided in the late 1980s.

    I have one good war story: I gave the booleans #t and #f each an identifying tag, so it didn't matter what the datum part of one was. When I wanted a Pixie Scheme routine to return #t or #f, I would just set the tag of the return value appropriately, and ignore the rest. But then I made a mistake in the routines that compared them for equivalence; they tested not only the tag but also the 32-bit datum with which it was associated. I had inadvertently created 2 to the 32 kinds of #t, all printing alike but no two equal. And I had done the same for #f. I was reminded of Arthur C. Clarke's short story, "The Nine Billion Names of God". And I was pleased to have modeled reality well, by creating almost enough kinds of truth for every human alive to have a different version. That might be sufficient even for politicians, religious authorities, and business executives.

  • "Why didn't you use (Object Pascal / Forth / C++ / Ada / Cobol / Java / Microsoft Basic / <whatever> )"

    Er, ah, um... because! That's why -- because! Seriously, I bought my Macintosh II because it was almost surely the most powerful personal computer system then available (in the second quarter of 1987), particularly for programs that required easy access to much memory. I knew C well, and there were good C development systems available for the Mac II. The only decent object-oriented development system available for the Mac at that time was Apple's Object Pascal, but I have never particularly liked Pascal. So I developed Pixie Scheme as a C program, using the Apple "Macintosh Programmer's Workshop" environment and compilers. There were no decent C++ compilers for the Macintosh when I started the Pixie Scheme project, so C++ was not an option at the time. (The C compiler that I started out with was not even ANSI-standard C.)

    Cobol would have been, ah, fascinating.

  • "I thought a main event loop was part of the One True Way to write Macintosh programs."

    Well, neener, neener, neener. And what's more, there isn't any Santa Claus.

  • "Why don't you ask for some particular amount in your request for a shareware donation?"

    I think it should be you who decides what my software is worth.

    I might not even ask for shareware donations at all, except that I am curious who uses Wraith Scheme, and where, and for what. I can get some idea of the first two by tracking shareware donations. Basically, I provide Wraith Scheme as a public service: I won't go on about how I think people ought to make some such use of their time and energy, but I do think so. I work professionally in computer science and am presently doing okay (knock on wood). Putting a useful piece of software into the field is one way of saying "thank you" to a lot of people who have made things easier for me, and is perhaps a way to acknowledge and encourage many others who have missed various boats that I have been lucky enough to catch. The present implementation of Wraith Scheme will set no records for high performance and will overwhelm no one with exotic features, but a reasonable, inexpensive Scheme implementation, on a computer as widely used and as easy to use as the Macintosh, is likely to be interesting to computer hobbyists and enthusiasts, and perhaps even useful for students and educators. So enjoy. And pass it on.

    And if you are feeling guilty about not sending me a shareware donation, send me some EMail, and tell me how much you like Wraith Scheme. Or if you don't like it, tell me why not and what I can do about it.

  • "Seriously, how much do you want for a shareware donation?"

    As I said before, there is an old Russian proverb: "Hope for the best, and expect the worst; thus you shall never be disappointed."

  • "What's it like, being a shareware developer?"

    It's poor for the wallet but great for the ego. During the first few months after the initial release of Pixie Scheme I barely received enough shareware donations to buy dinner in a cheap place. By dividing the total shareware donations I received by the time I spent on the project, I find I was working for about two cents an hour -- a rate that Scrooge McDuck might have paid. But for a month or so after each release, I made an offer over the "usenet" computer network, to provide a copy of the program to anyone who mailed me a disc, a return mailer, and sufficient postage. I received requests from places as remote as Finland and New Zealand: Pixie Scheme truly achieved world-wide distribution, long before the Internet came of age. I was also pleased to find that the Boston Computer Society Macintosh Users Group had put the first release of Pixie Scheme on one of their "developer" discs, and had also included it on a CD ROM of public domain and shareware software.

    What's more, it turned out that a modest proportion of the folks who did send me a shareware donation didn't send just the dollar that I suggested for Pixie Scheme; frequently they sent as much as ten dollars. Thus I can demonstrate on the basis of actual experience that my software was worth more money than I asked for it. Who else in the software-development industry can make such a claim? Usually it is very much the other way around.

  • "Are you, or were you an 'official' Apple developer?"

    I was an "Apple Associate" during the latter part of the time I was working on Pixie Scheme. I am currently (2009) an Apple developer with an ADC "Select" membership.

  • "What was it like, being an Apple Developer in the old days?"

    Each year they sent out several GBytes of interesting stuff on CD-ROM, as well as lots of printed documents. If I had wanted to upgrade my system, I could have done so at a discount. The folks at Developer Technical Support were very helpful. It took longer than I expected to get a reply to my application to register some of the resource types used in Pixie Scheme. I sent them a product: Perhaps they were more accustomed to vaporware.

  • "Tell us something about yourself."

    Life happens while you are making other plans: I am a retread astrophysicist who has worked as flight instructor, consultant to the U. S. Department of Energy, and computer scientist. My doctoral thesis project used a spacecraft instrument (1975 Apollo-Soyuz Test Project) to study the interstellar medium.

    My introduction to computer science was writing small Fortran programs to reduce thesis data. (I thought they were big Fortran programs at the time.) I have worked on parallel processing -- SIMD and MIMD, hardware and software. I once helped build a CyberSpace interface. I have worked in what marketeers call "artificial intelligence" but is better termed "system programming in Lisp". And I have won Rogue many times, without resorting to Wizard mode to do so.

    I am a science fiction fan, an English Regency ballroom dancer, and an occasional bicyclist, rose grower and amateur astronomer. I play guitar and occasionally build simple musical instruments. I live in Palo Alto, California, with too many cats and not enough time.

    Answers to commonly-asked personal questions: blue, chocolate, chunky, single, and only if the esteem is mutual.

    I have a personal web site: http://web.mac.com/Jay_Reynolds_Freeman.

  • "What did you think of the Macintosh then?"

    It was the least unsatisfactory personal computer I knew of, but that was an easy win, considering the competition. It needed a real operating system, decent graphics, and a decent user interface. Programming with the old ToolBox was like trying to wash your hands with rubber cement. And oh, yes, they should have given them away free, so everybody could have had one.

  • "What do you think of the Macintosh now?"

    It is the least unsatisfactory personal computer I know of, but that's an easy win, considering the competition. The operating system, graphics, and user interface are much improved. Programming with the current Apple development environment is still pretty Byzantine, but if you can make it through the maze of twisty little class definitions, interfaces, and secret passageways, all alike, you have the full might and majesty of the entire Byzantine Empire -- that would be Apple -- on your side, and there is something to be said for that. And they still should give them away free, so everybody could have one.

  • "Are you planning any more projects?"

    Well, the garden needs some work, and... oh, you meant programming projects. Let's just say that I have had lots of cats.

  • "Do you have any last bits of wisdom or words of advice for users?"

    Do you believe in users? Never mind. Anyway, remember, "lambda" is spelled with a 'b'. And I was just kidding about Santa Claus.

Thanks To:

    (Pretty much in alphabetical order, except for the cats, who of course have the last word.)

  • Apple Incorporated, for providing excellent software development environments and numerous examples of code, all for free.

  • The members of the Silicon Valley "Cocoaheads" group, for advice about the Wraith Scheme user interface.

  • The creators of the various "Rn" Scheme reports, for providing much clear explanatory text and numerous examples -- both simple and subtle -- of how the language is supposed to work. I am particularly grateful for the example implementations of derived expression types in section 7.3 of the R5 report, which formed the basis of the implementation of most of those types in Wraith Scheme.

  • Mike Deering, for lengthy discussions of tagged-pointer Lisps.

  • Libby Hudson, for moral and immoral support.

  • Sandy Lerner, for encouragement in development and advice on commercial prospects.

  • Tim May, for humor, and for the chance to play with his computer, software and other toys.

  • Charles Smith, for hiring me into a major artificial-intelligence laboratory.

  • Pixie, Wraith, and numerous other cats, for love and purrs, and for the sharing of their ineffable names.

    Notwithstanding the honest acknowledgments and grateful thanks given above, I am confident that all errors and misfeatures in Wraith Scheme are nobody's fault but mine.

-- Jay Reynolds Freeman, November 2009

Wraith Face