[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Using Macros in Lisp



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