Michael Price writes:
On 8/24/06, Marco Antoniotti marcoxa@cs.nyu.edu wrote:
Hi
I would like to suggest a feature for SLIME taken from Lispworks.
In LW I can type
prompt> member 42 '((3 2 3) (1 42 33) (42 11 22)) :key #'second ((1 42 33) (42 11 22))
I.e. a line gets parenthesized if it is not already an expression (of course there are cases where things get hairy, but in general I find it useful).
CL-USER> (defvar a 4)
A CL-USER> (defvar b 9)
B CL-USER> a b
4 CL-USER> 9 CL-USER> (defun a (x) (sqrt x))
A CL-USER> (a b)
3.0
So what happens in lispworks if I do this:
CL-USER> a b
Do I get a separate 4 and 9 again or do I get 3.0?
Well, you can still get the variables with list or values:
(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* "~&") (finish-output)) (condition (ERR) (format *error-output* "~&~A: ~% ~S~%" (class-name (class-of err)) err) (finish-output))))
(defun line-repl () (do ((+eof+ (gensym)) (hist 1 (1+ hist))) (nil) (format t "~%~A[~D]LINE> " (package-name *package*) hist) (finish-output) (handling-errors (let ((operator (read *standard-input* nil +eof+))) (if (member operator '(quit exit continue) :test (function equal)) (return-from line-repl) (let ((arguments (read-line *standard-input* nil +eof+))) (if (eql arguments +eof+) (return-from line-repl) (setf - (read-from-string (format nil "(~A ~A)" operator arguments)))))) (let ((results (multiple-value-list (eval -)))) (setf +++ ++ ++ + + - /// // // / / results *** ** ** * * (first /))) (format t "~& --> ~{~S~^ ;~% ~}~%" /) (finish-output)))))
[61]> (line-repl)
COMMON-LISP-USER[1]LINE> defvar a 3 --> A
COMMON-LISP-USER[2]LINE> defvar b 6 --> B
COMMON-LISP-USER[3]LINE> defun a () 3.14 --> A
COMMON-LISP-USER[4]LINE> a --> 3.14
COMMON-LISP-USER[5]LINE> defun a (x) (* 3.0 x) --> A
COMMON-LISP-USER[6]LINE> a b --> 18.0
COMMON-LISP-USER[7]LINE> list a b --> (1 6)
COMMON-LISP-USER[8]LINE> values a b --> 1 ; 6
COMMON-LISP-USER[9]LINE> quit NIL [62]>
Using an implementation dependant function such as #+clisp EXT:ARGLIST you can even read the first token, see if it's a function, get the argument list expected for the function and further parse the number of sub expressions needed. You can even do it recursively, to parse correctly expressions such as:
append cons car items cddr items cons parse-integer "123" :radix 5 nil
to:
(append (cons (car items) (cddr items)) (cons (parse-integer "123" :radix 5) nil))
The limit goes when you want to use functions with &REST:
list + 1 2 3 - 4 5 * 6 7 0
is totally ambiguous. For &rest, you have to reintroduce parentheses, or at least an end of list mark:
list + 1 2 3) - 4) 5 * 6 7 0
can then be parsed as:
(list (+ 1 2 3) (- 4) 5 (* 6 7 0))
while:
list + 1 2 3 - 4 5)) * 6 7 0
can then be parsed as:
(list (+ 1 2 3 (- 4 5)) (* 6 7 0))
You still have a problem with lisp-2 ambiguous symbols:
cons car list 2 3
could be either:
(cons (car list) 2) 3 (cons (car (list 2)) 3) (cons (car (list 2 3)))
If we assume we have all the input before parsing it, we can still resolve some of these ambiguities (only the second one would be a correct single form), but there could remain a lot of unresolvable cases.
Parentheses are a necessity in lisp-2 with &rest.