[chicago-lisp] (no subject)

dkixk at earthlink.net dkixk at earthlink.net
Sat Dec 9 00:37:10 UTC 2006


-----Original Message-----
>From: John Quigley <jquigley at jquigley.com>
>Sent: Dec 8, 2006 2:20 PM
>To: Chicago LISP <chicago-lisp at common-lisp.net>
>Subject: Re: [chicago-lisp] (no subject)
>
>dkixk at earthlink.net wrote:
>> This has nothing to do with "highly optimized code" in the sense of C being optimized.
>
>Yea, that was a poor statement on my part, and was meant as a mildly 
>sarcastic remark ('mildly,' because I do system development in C, and I 
>do like the language).
>
>The point I didn't take time to develop in that email: that a Lisp's 
>lack of tail-call optimization at the compiler level isn't an important 
>issue for me.  Nor does it prevent me from writing code in a functional 
>way.  While it puts more responsibility on the developer, having the 
>choice of using standard recursion can be beneficial (if you want 
>complete stack back-traces, for instance).

I totally agree.  Whatever does or does not happen at the compiler level is not important.  What I do think is important is whether or not one style is limited within the framework of the language I'm using.  So to try and put an end to this debate once and for all, let's try an objective experiment.

PG-USER> 
;;;; Compile file d:/tmp/duff.lisp ...
;;; Compiling file d:\tmp\duff.lisp
; While compiling REPL-WITH-LOOP:
Warning: Variable DUFF-*** is never used.
;;; Writing fasl file d:\tmp\duff.fasl
;;; Fasl write complete
PG-USER> (with-open-file (s "duff.lisp")
           (loop for line = (read-line s nil) while line do
                 (princ line) (terpri)))
(in-package :pg-user)

(defun duff-user-input ()
  "(make-array (expt 10 4) :initial-element 0)")

(defun repl-with-loop ()
  (handler-case
      (loop for duff-*** = nil then duff-**
            for duff-** = nil then duff-*
            for duff-* = (eval (read-from-string (duff-user-input)))
            finally (return-from repl-with-loop :not-limited))
    (error () :limited)))

(defun repl-with-funk (&optional duff-* duff-** duff-***)
  (declare (ignore duff-***))
  (handler-case
      (repl-with-funk (eval (read-from-string (duff-user-input)))
                      duff-* duff-**)
    (condition () :limited)
    (:no-error (x) (or x :not-limited))))
NIL
PG-USER> (time (repl-with-funk))
; cpu time (non-gc) 40 msec user, 0 msec system
; cpu time (gc)     381 msec user, 0 msec system
; cpu time (total)  421 msec user, 0 msec system
; real time  481 msec
; space allocation:
;  12,512 cons cells, 14,344,840 other bytes, 0 static bytes
:LIMITED
PG-USER> (time (eq * (repl-with-loop)))

... but I still don't have the answer to whether or not (eq (repl-with-funk) (repl-with-loop)).   I have no evidence yet with which to try and convince you so I'll just forget about it until I know the result.  My intuition that tail-call elimination is somehow fundamental to a functional functional style in a "lisp" will have to remain conjecture.  Either way, nothing prevents you from writing funktional code but I'll keep using things like loop.  Again, until that computation finishes.  For now, I guess we'll just have to agree to disagree.



More information about the Chicago-lisp mailing list