kib2 wrote:if fexprs were so good, why do they disappear from CL ?
In my opinion it is bad design. It is justified by fact that fexprs are hard to understand by programmers, and trouble for compiler writers. For example, one of the arguments is that if you have fexprs, compiler cannot optimize (
f (+ 1 1)) because it doesn't know whether
f is fexpr of function. Function doesn't care, but fexpr does.
Kent Pitman wrote historically important article
Special forms in Lisp about that. It took me long time to understand it, but I think it is all more-less wrong.
- P.Seibel said :
And, in a compiled Lisp program, that new language is just as efficient as normal Lisp because all the macro code--the code that generates the new expression--runs at compile time. In other words, the compiler will generate exactly the same code whether you write
. Is this statement true for newLisp too ?
If Newlisp has optimizing compiler, it could be the truth. With "ordinary" compiler, compiled code would be bit slower. Only a bit, however. But, as
Cormullion said, there is no compiler for Newlisp at all, it is interpreter, so every function and macro you write is necessarily slower than primitives.
However, that macroexpansion phase that
Siebel described enthusiastically is not really good thing in every situation. Look at following CLisp code:
Code: Select all
[1]> (defun pump-l(n x)(setf L ())(dotimes(i n)(push x L)))
[2]> (defun eval-whole-L()(dolist (f L)(eval f)))
[3]> (pump-l 100000 '(progn (setq A ())(push 0 A)))
[4]> (time (eval-whole-l))
Real time: 3.046875 sec.
Run time: 3.046875 sec.
Space: 91965272 Bytes
GC: 144, GC time: 0.375 sec.
This is relatively slow - because it contains macro push. Now, look what happens if I avoid macro (push 0 A), replacing it with its expansion (setq A (cons 0 A)) manually:
Code: Select all
[5]> (pump-l 100000 '(progn (setq A ())(setq A (cons 0 A))))
[6]> (time (eval-whole-l))
Real time: 0.1875 sec.
Run time: 0.1875 sec.
Space: 800008 Bytes
GC: 1, GC time: 0.015625 sec.
You see, 15 times faster code and 100 times less memory use. Why? In this example, code is generated - and then evaluated during runtime. Hence, because code contained
push macro, macroexpansion happened during runtime - there was no choice. And that macroexpansion took some 95% of total processing time. So, CL macros are not really suitable for code generated and evaluated during runtime.