Kaz Kylheku <kaz@ashi.footprints.net> wrote:
+---------------
| A useful REPL is not literally a naive (LOOP (PRINT (EVAL (READ))));
| that is just the high level concept which explains the essential
| actions of the listener. A useful REPL must expect the evaluated form
| to return multiple values and handle them, for example using logic
| like
|
| (dolist (value (multiple-value-list (eval ...))))
| (print value)))
|
| And of course (multiple-value-list (values)) returns an empty list, so
| nothing is printed.
+---------------
IIRC, somebody posted a nice little FORMAT for that a while back:
(defun mv-eval-print (form)
(format t "~&~{~S~%~}" (multiple-value-list (eval form))))
A useful REPL might also print a prompt, which you want the user
to be able to customize (perhaps heavily, with line numbers and
current package and stuff), so you start to get something like the
following pattern:
(defvar *my-prompt* "> ")
(defun my-repl ()
(loop
(if (or (functionp *my-prompt*)
(and (symbolp *my-prompt*) (fboundp *my-prompt*)))
(funcall *my-prompt*)
(format t "~&~a" *my-prompt*))
(force-output) ; push out partial line
(mv-eval-print (read))))
Of course, after playing with that for about five minutes,
you'll probably decide you really want to handle EOF nicely,
and maybe catch runtime errors and call the debugger yourself
(so you can wrap a couple of top-level restarts around all that),
maybe even special-case a few top-level forms as "commands"
(e.g., ":q" to exit), but that's a story for another time...
-Rob
-----
Rob Warnock, PP-ASEL-IA <rpw3@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607