REPL
The Read Eval Print Loop of a Lisp listener.

Implementation of a REPL in Common Lisp

The most basic REPL implementation is just what it says:

NOTE: the code presented here lacks flushing (call to finish-output). It'll have to be updated

Given the order of evaluation imposed by the parentheses, READ is evaluated first, then EVAL, then PRINT, then LOOP. Hence REPL.

cl-user> (Loop (Print (Eval (Read))))
(+ 2 3)

5 (list 1 'apple 2 'orange)

(1 apple 2 orange) ; Evaluation aborted on #<com.informatimago.signal:user-interrupt #x302004E56F0D>.
cl-user> 

A more sophisticated REPL (conforming to the ANSI Common Lisp specification) could be:

(defmacro handling-errors (&body body) `(handler-case (progn ,@body) (simple-condition (err) (format *error-output* "~&~A: ~%" (class-name (class-of err))) (apply (function format) *error-output* (simple-condition-format-control err) (simple-condition-format-arguments err)) (format *error-output* "~&")) (condition (err) (format *error-output* "~&~A: ~% ~S~%" (class-name (class-of err)) err)))) (defun repl () (do ((+eof+ (gensym)) (hist 1 (1+ hist))) (nil) (format t "~%~A[~D]> " (package-name *package*) hist) (handling-errors (setf +++ ++ ++ + + - - (read *standard-input* nil +eof+)) (when (or (eq - +eof+) (member - '((quit)(exit)(continue)) :test (function equal))) (return-from repl)) (setf /// // // / / (multiple-value-list (eval -))) (setf *** ** ** * * (first /)) (format t "~& --> ~{~S~^ ;~% ~}~%" /))))

It provides the standard REPL variables, -, +, ++, +++, *, **, ***, /, // and ///, and handle errors reporting a message. In CL implementations, the debugger would be invoked upon errors.

cl-user> (repl)

COMMON-LISP-USER[1]> (* 3 4)

 --> 12

COMMON-LISP-USER[2]> (/ 1 0)

division-by-zero: 
  #<division-by-zero #x302004F8497D>

COMMON-LISP-USER[3]> (quit)
nil
cl-user> 

Examples and Comparison of REPL

Here are two examples of REPL interaction.

The first is with an ANSI Common Lisp implementation; all Common Lisp implementations have similar REPL, but they differ in the set of command they offer in the debugger. slime covers the differences with a common layer.

The second is with an ANSI C implementation. C implementations don't often provide a REPL, having an heritage of batch processing much more than interactive development, but there are a few C implementations that provide more or less limited REPL.

Langage: ANSI Common Lisp; Implementation: clisp

[pjb@kuiper :0 ~]$ clisp -ansi -norc
  i i i i i i i       ooooo    o        ooooooo   ooooo   ooooo
  I I I I I I I      8     8   8           8     8     o  8    8
  I  \ `+' /  I      8         8           8     8        8    8
   \  `-+-'  /       8         8           8      ooooo   8oooo
    `-__|__-'        8         8           8           8  8
        |            8     o   8           8     o     8  8
  ------+------       ooooo    8oooooo  ooo8ooo   ooooo   8

Welcome to GNU CLISP 2.49+ (2010-07-17) <http://clisp.org/>

Copyright (c) Bruno Haible, Michael Stoll 1992, 1993
Copyright (c) Bruno Haible, Marcus Daniels 1994-1997
Copyright (c) Bruno Haible, Pierpaolo Bernardi, Sam Steingold 1998
Copyright (c) Bruno Haible, Sam Steingold 1999-2000
Copyright (c) Sam Steingold, Bruno Haible 2001-2010

Type :h and hit Enter for context help.

[1]> (defun f (x) (if (< x 1) 1 (* x (f (1- x)))))
F
[2]> (f 5)
120
[3]> (defparameter *s* 0)
*S*
[4]> (loop for i from 0 to 5 do (incf *s* (f i)))
NIL
[5]> *s*
154
[6]> (loop for i from 0 to 5 do (incf *s* (f (/ i))))

*** - /: division by zero
The following restarts are available:
ABORT          :R1      Abort main loop
Break 1 [7]> :bt 4 1
<1/246> #<SYSTEM-FUNCTION SHOW-STACK> 3
<2/239> #<COMPILED-FUNCTION SYSTEM::PRINT-BACKTRACE>
<3/233> #<COMPILED-FUNCTION SYSTEM::DEBUG-BACKTRACE>
<4/224> #<SYSTEM-FUNCTION SYSTEM::READ-EVAL-PRINT> 2
<5/221> #<COMPILED-FUNCTION SYSTEM::BREAK-LOOP-2-3>
<6/217> #<SYSTEM-FUNCTION SYSTEM::SAME-ENV-AS> 2
<7/203> #<COMPILED-FUNCTION SYSTEM::BREAK-LOOP-2>
<8/201> #<SYSTEM-FUNCTION SYSTEM::DRIVER>
<9/161> #<COMPILED-FUNCTION SYSTEM::BREAK-LOOP>
<10/158> #<SYSTEM-FUNCTION INVOKE-DEBUGGER> 1
<11/147> #<SYSTEM-FUNCTION /> 1
[146] EVAL frame for form (/ I)
Printed 11 frames
Break 1 [7]> i
0
Break 1 [7]> :q
[8]> (loop for i from 0 to 5 do (incf *s* (f (/ (1+ i)))))
NIL
[9]> *s*
160
[10]> (setf *s* 0)
0
[11]> (loop for i from 0 to 5 do (incf *s* (f (/ (1+ i)))))
NIL
[12]> *s*
6
[13]> (f (/ 1 5))
1
[14]> (f 30)
265252859812191058636308480000000
[15]> (quit)
Bye.
[pjb@kuiper :0 ~]$ 

Langage: ANSI C; Implementation: ch

[pjb@kuiper :0 ~]$ ch
                              Ch (64-bit)
                  Standard edition, version 7.0.0.15151 
              Copyright (C) SoftIntegration, Inc. 2001-2011
                     http://www.softintegration.com
/home/pjb> int f(int x){ return x<1?1:x*f(x-1); }
int f(int x){ return x<1?1:x*f(x-1); }
/home/pjb> f(5)
f(5)
120 
/home/pjb> int s=0;
int s=0;
/home/pjb> {int i; for(i=0;i<=5;i++){ s+=f(i); }}
{int i; for(i=0;i<=5;i++){ s+=f(i); }}
/home/pjb> s
s
154 
/home/pjb> {int i; for(i=0;i<=5;i++){ s+=f(1/i); }}
{int i; for(i=0;i<=5;i++){ s+=f(1/i); }}
WARNING: integer divide by zero 
Segmentation fault
[pjb@kuiper :0 ~]$