[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Using Macros in Lisp
- To: info-macl@cambridge.apple.com
- Subject: Re: Using Macros in Lisp
- From: dmg@goldilocks.LCS.MIT.EDU
- Date: Wed, 06 Mar 91 11:06:30 EST
- In-reply-to: Your message of Wed, 06 Mar 91 08:27:06 -0600. <9103061427.AA22412@tartarus.uchicago.edu>
I have a few comments regarding the use of macros, and CommonLisp
in general.
Avoiding any language extension is like avoiding the emergency brake
in your car. The facility is there for a reason, use it when you need
to but don't feel the need to use it to be cool just because its there.
Because if you don't understand when to use it, you'll likely use it
inappropriately. The examples that Tom McDougal supplied rather clearly
illustrate this point.
----------------
In the first example, we have a macro that at best replaces a type
check that is directly supported by the language (and thus possibly
directly supported by the compiler).
INSIST = CHECK-TYPE in Common Lisp
Thus what you want to write is:
(check-type foo (and numberp (eql 0)))
It is:
1) much more likely to be compiled efficiently
2) clearer to others who know Common Lisp
3) one less idiosyncrasy in the program
The moral here is: don't implement what the language already supports.
----------------
In the second example, there are a few problems.
1) Despite the name of the macro, it does not implement iteration
Iteration and recursion are orthogonal concepts. (Whether the
compiler implements tail recursion is irrelevant.)
2) Regardless of how smart the compiler is, say what you mean. The issues
behind optimization of Lisp are quite complex and rather subtle in
many cases. Just because something looks like it can be optimized
doesn't really mean it will. The quality of optimization in Lisp
compilers today varies greatly.
3) Again, if the language supports a mechanism directly, the chances
are that you will do no better writing your own hack, unless you
know that the compiler is not optimizing what it could. At which
point you should contact the people who support the compiler. Either
you are right and they will improve the compiler, or there are some
issues that you haven't considered, at which point you can go ahead
and write that macro.
If you want to "march down a list until you find something"
use FIND -- That's why its there.
4) Personally, I would argue that there's no need for a macro here
at all. This is a matter of style which is in turn, no matter what
"experts" might want you to believe, a matter of personal taste.
However, importing semantically redundant features from other
languages is difficult to justify, except on the basis of
personal preference. If you're going to write something in Common
Lisp, which other people who use Common Lisp are likely to want to
read, why confuse them with redundant constructs from a language they
may have never used?
Try this:
(defun fact (x)
(let ((result x))
(loop
(if (= (decf x) 1)
(return result)
(setq result (* result x))))))
(Actually, if I remember correctly, the 68xxx machines set the ZERO
bit on load, so for large X, it's probably faster to go the extra
loop cycle to save the compare instruction. Of course, it's a minor
issue and not the type of thing that a general lisp programmer should
worry.)
I would expect that most compilers will have a hard matching this
code, and are not going to do better. If the compiler does not
implement tail-recursion and use special entry-points for internal
functions, you're going to lose quite badly.
----------------
When learning how to use the language, nothing beats compiling
different forms and looking at the disassembly. This forum,
for questions and answers, is a good place for these types of
discussions, especially when the implementers are willing to
talk concretely about the computational issues surrounding the
question. Perhaps we could hear more from them on this issue.
-dmg