Why don't people like lisp?

Peter Seibel peter at javamonkey.com
Wed Oct 22 04:05:39 EDT 2003


"Andrew Dalke" <adalke at mindspring.com> writes:

> Peter Seibel:
> > Okay, here's a Common Lisp version. Because Lisp functions take either
> > keyword or positional arguments, I choose to make the generated
> > functions use keyword arguments. But the variables are gathered in the
> > right order, so take out the '&key' below to use positional arguments:
> 
> Cool code.  I like that it identifies some of the error locations.
> 
> >   * (funcall (compile-rpn "a b +") :a "foo" :b 2)
> >   Error: `"foo"' is not of the expected type `NUMBER'
> 
> My Python code reports a line number for this.

Right. Well that's one disadvantage, such as it is, of having the
compiler built in--I'm at the mercy of its error reporting and Lisp
isn't big on line-numbers, perhaps because many definitions don't come
from a file. What I didn't show in the output was that I was actually
dropped into the debugger at that point so had all the capabilities
that it provided to figure out what was going wrong. Anyway, that's
the price I pay for getting machine code I guess. I could, if it was
really important wrap all the function calls in condition handling
code that reported the line number but it didn't seem worth it.

> In my reply to Erann Gat I noted that his eval approach might
> exclude the possibility of using names like 'a)' as identifiers. (I
> don't know if it does, because I don't know enough Lisp.)
> 
> My AST solution could easily be changed to support that case, as
> well as variable like ";;b" and "#c" and ":d:".
> 
> I'll ask the same of you. Does your code require that the RPN names
> also be valid Lisp tokens? If so, what happens if it isn't?

Sure. I just used the built in Lisp reader because the syntax you
specified was compatibile. But if I wanted to allow names including
special characters I could either tweak the readtable so the Lisp
reader didn't treat them as special or I could do something like this.
Notice that the actual change to the parse function is to one function
call, replacing a call to the built-in READ-FROM-STRING with my own
next-token function. The rest of the patch is my own simple tokenizer.
(And I had to redefine variablep to allow weird variable names.) The
tokenizer could probably be written better but it's late here and I
should be in bed.

==== //depot/lisp-book/code/rpn.cl#1 - /home/peter/localperforce/lisp-book/code/rpn.cl ====
@@ -10,7 +10,7 @@
 (defun parse (input)
   (let (stack variables (idx 0))
     (loop
-      (multiple-value-bind (tok next-idx) (read-from-string input nil nil :start idx)
+      (multiple-value-bind (tok next-idx) (next-token input :start idx)
         (labels 
             ((line-number () (1+ (count #\Newline input :end idx)))
              (pop-arg ()
@@ -25,8 +25,35 @@
            (t (error "Invalid token ~a at position ~d (line ~d)." tok idx (line-number))))
           (setq idx next-idx))))))
 
-(defun variablep (sym)
-  (and (symbolp sym) (every #'alpha-char-p (string sym))))
+
+
+(defun next-token (input &key (start 0))
+  (multiple-value-bind (str end) (next-string input :start start)
+    (when str
+      (values 
+       (if (digit-char-p (char str 0))
+         (read-from-string str nil nil)
+         (intern (string-upcase str)))
+       end))))
+  
+(defun next-string (input &key (start 0))
+  (let ((real-start (skip-white-space input :start start)))
+    (loop for idx from real-start below (length input)
+        while (not (white-space-p (char input idx)))
+        finally (return
+                  (values 
+                   (if (= real-start idx) nil (subseq input real-start idx))
+                   (skip-white-space input :start idx))))))
+
+(defun skip-white-space (input &key (start 0))
+  (loop for idx from start below (length input)
+      while (white-space-p (char input idx))
+      finally (return idx)))
+
+(defun white-space-p (char)
+  (member char '(#\Space #\Newline #\Tab)))
+
+(defun variablep (sym) (symbolp sym))


> (Looking at it, the key line is
> >              ((not tok)               (return `(lambda (&key ,@(nreverse
> variables)) (prog1 , at stack))))
> 
> but I don't know what @() does nor what happens if a "strange"
> value is used as the list of keywords)

Actually the key line is the one I patched above. This is just
generating the form which Lisp knows how to compile. But since Lisp
symbols can actually contain any character, as long as they're
properly escaped I have no real problems.
> 
> > And for grins here's the x86 machine code generated for the first
> function:
> 
> I was never any good at Intel assembly, and I thankfully haven't
> touched it in about 15 years.  I was trying to figure out if it
> optimized the additions into 15**a, but I could see neither the
> sequence 1, 2, 3, 4, 5 nor the value 15 (octal 17, hex F) anywhere
> in the code.  Pointers?

Well, I know less about it than you. I just threw that in to point out
that my 24-line compiler generates machine code.

-Peter

-- 
Peter Seibel                                      peter at javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp




More information about the Python-list mailing list