From Gambit wiki
For me, Scheme and LISP are interesting because of
- their simple syntax and code/data equivalence
- their abstract ideas which are directly visible in the language
- the ability to debug and change the system at runtime
Scheme in particular has powerful building blocks like
Scheme implementations vary widely in usability and debugging features. Gambit is one of the better ones.
Eventually I'll add more details here.
I'm still looking for a good portable program.
Some of the features I'd like to see in the existing or new REPLs. These are the ones I don't know how to implement, but not the most controversial or far-reaching ones. Eventually I may move these or link to them.
Show the prompt after suspending and resuming the interpreter. On BSD systems this requires telling the kernel to not restart the call to
read that was interrupted -- instead the interpreter must reset the TTY modes, reprint the prompt, and then restart the read itself.
Allow a key to cancel the entire form being read (I like the idea of escape u, since I can type it as option-u and it makes a nice analogy with ctrl-u).
This may require
os_tty.c to throw an exception which Scheme code catches. Some variant of datum-parsing or expression-parsing error would be appropriate. Or
os_tty.c may be able to return a special value. It could be called
#!cancel by analogy with
#!eof, or it could be a status code that has no global name.
Print prompts for the second and later lines of a form.
Store forms rather than lines in the input history? (Store newlines, allow them to be redisplayed and edited.)
Have a way to send EOF and interrupts.
Have function keys (F8-F12) that do the same thing as in the other REPLs.
Although it is based on a text editor, it still echoes typed-ahead input twice (once when it is typed and a second time when it is used). Would eliminating that be useful? See below for one way.
None of the above
(more than one of the implementations, or some new implementation)
If a REPL has editing of the entire form being read, a "cancel" key is not necessary. Instead the form should be read from the beginning each time the user tries to input it.
I'm not sure if I like the traditional idea of prompts. They disrupt the indentation and make copies of sessions difficult to read/reinterpret. These problems undoubtedly have some better but complicated solution.
If the REPL knows which characters the reader has consumed, and the REPL can position the insertion point anywhere in the text, then the REPL can allow typing ahead of input (and even editing of unsent input) while also saving an accurate record of the sent input and output (with no duplication). The REPL simply moves the cursor past input as it is sent, or moves the cursor backward if the reader unreads the input. Then the REPL inserts the output into the buffer at the cursor (just after the input that produced it).
All of the REPLs could use more key equivalents for comma commands. Also the keys should work only when the commands are legal. The reader needs to tell the REPL when that is (specifically outside another form). The current trick of surrounding the expansion by extra characters can't really solve the problem and looks unnatural.
When the interpreter signals a datum or expression error, it expects to read a new form from the beginning. If the REPL knows the type of the error and can position the insertion point anywhere in the text, then it can put the error before the form and allow the user to edit and resend the form. Resending the form would erase the old error and perhaps print a new one in the same place. This is a first step toward having the REPL show only the interpreter's current view of the REPL world (line history, value history, etc.). A log is an important idea, but I suspect people might want to see only the current state in practice.
Evaluation errors may happen after side effects that can't be undone, so the REPL should read new input text after an evaluation error, as it does now.
Allow the reader to call user-supplied procedures per-character, per-line, or per-form. The reader may also need to call an "uncharacter" procedure because of the syntax of Scheme tokens.
The reader knows about ports, but these user procedures should know about the channels that contain the ports (so that they can send output to the same terminal the reader is getting input from).
Per-character and per-line and uncharacter procedures are needed to implement some of the features listed above. I don't know what per-form is good for but it seemed like a natural complement to the others.
These points bring up issues I don't know how to deal with. For example, Scheme code can always read its own forms or characters while it's running. There are undoubtedly other difficult questions to answer.