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

macrolet



[Aside: I don't think the purpose of the Common-Lisp list is to discuss
 the choice of examples in an already published book, except perhaps,
 in some cases where such examples are erroneous, misleading or
 contradictory. I don't think this is such a case. Personally, I think
 this would have been a good issue on which to get some private help
 rather than sending mail to this list.]

    Date: Thu, 9 Jul 87 13:04:27 EDT
    From: vax135!lcuxle!elia@ucbvax.Berkeley.EDU (Weixelbaum Elia)

    When I read the explanation for macrolet on page 114, Cltl, I had a few
    problems with the 'clear' example:

    (defun foo (x flag)
      (macrolet ((fudge (z) ... `(if flag (* ,z ,z) ,z))) ...))
    ...
    (setq flag t) ==> t
    (foo 10 nil) ==> 31 (since flag is taken as nil).

    A more illustrative example might be to change the body of fudge to:

    `(if ,flag (* ,z ,z) ,z)	; Evaluate flag within macro expansion
    ...

Your "fixed" code above fails to proclaim FLAG special. (Also, being
special CLtL suggests the variable be called *FLAG* unless you have a
compelling reason not to name it so.) Using DEFPARAMETER (or DEFVAR)
rather than SETQ to set FLAG would have accomplished this.

But more importantly, you have confused compilation time with load time.
The SETQ (or even the DEFPARAMETER initialization) will not take place
until the code is loaded, which is generally -after- the macro has
expanded (except in the special case of interactive use, such as you
probably did to test your example). You would have to have written the
SETQ, DEFVAR, or DEFPARAMETER inside (EVAL-WHEN (EVAL COMPILE) ...) to
assure that the assignment happened at the right time (ie, before the
macroexpansion).

I won't bother to address the issue that your suggested rewrite didn't
include the removal of the FLAG variable (which is now unused) and the
resulting visual confusion which might ensue from having a function bind
a variable and then not refer to it while at the same time referring to
a variable by the same name evaluated in some other context.

All this aside, however, the code you suggest is not in a style that I
think I would encourage people to use. The need to use global state is
lamentable but often necessary. The use of compile time global state is
even trickier and more to be avoided whenever possible just because of
the confusion that can result about whether the compile time and runtime
environment are the same or not. This varies a lot from dialect to
dialect and is an easy place for code portability to be impacted.
Encouraging a style which is likely to lead to trouble in portable
programming is probably not wise. The example on p114 does not
illustrate the full power of macrolet, but it does illustrate a fairly
typical example of the way in which it is intended to be used, and
that's what's important.