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

macros...



    Date: Wed, 8 Apr 1992 03:33 PDT
    From: JAN92@uno.cc.geneseo.edu

    Hello --

    I am having a problem concerning parameters and macros...

    I ultimately want to define this function as a macro:

    (defun b-tree-insert (tree foo)
      (cond ((not (boundp tree))
	     (list 'setf tree
		   (list 'make-node foo)))
	    ((null tree)
	     (list 'setf tree
		   (list 'b-tree-insert-aux tree foo)))
	    (t
	     (list 'b-tree-insert-aux tree foo))))
         
We will postpone for a while the question of why you want this to
be a macro.

Since b-tree-insert is currently a function, the arguments are
evaluated before the function is invoked.  [I think that this is
your problem, but I'm not sure because I don't fully understand
your example.  Where did the symbol LAOS come from, and why would
you expect b-tree-insert to put ZETA in the output?  I will
assume that LAOS was a typo for ZETA.]  Thus, the value of the
TREE parameter in your function is not the symbol ZETA, but
rather the value of the symbol ZETA, NIL.  In order to pass the
symbol ZETA in to your function you have to quote the first
argument to b-tree insert.  If you had written this as a macro,
then the TREE parameter would in fact have the symbol ZETA as its
value (since the arguments to a macro are not evaluated).

    ? (setf zeta nil)
    nil
    ? (setf foo '(23 (e 1) (g 1)))
    (23 (e 1) (g 1))
    ? (b-tree-insert laos foo)
    (setf nil (b-tree-insert-aux nil (23 (e 1) (g 1))))

	  ^^^  

    It is here where I want "zeta" and not "nil", but for some reason I can't get
    around this.  I was thinking that maybe I could somehow access the name slot
    of the variable "zeta", but I can't seem to find the function to access it.
    Suggestions?

Even once you quote the first arg you have problems.  Now that
the value of the TREE parameter is the symbol ZETA, the various
COND clauses that expect to be looking at the value of ZETA need
to be updated to explicitly extract the SYMBOL-VALUE of ZETA.

You may be trying to do too much at "macro-expansion" time.  I
assume (again) that the main point of wanting this to be a macro
is so that you don't have to quote the tree argument all the time
and deal with its initial value.  Here is a macro that writes
very simple Lisp code that determines at run-time whether the
specified symbol already has a value (in which case we assume
that the value is a tree node) or not (in which case we
initialize that tree-naming-symbol to a tree node).  This example
uses the "backquote" mechanism, a powerful tool for writing macro
bodies (or other Lisp forms).  I can't explain the entire
facility here (it is documented in CLTL), but basically backquote
is like regular quote except that subforms preceeded by comma
characters are evaluated.  Thus `(foo (+ 4 5) ,(+ 4 5)) evaluates
to (foo (+ 4 5) 9).


(defmacro b-tree-insert-macro (tree-name item)
  `(if (or (not (boundp ',tree-name))
	   (null ,tree-name))
       (setf ,tree-name (make-node ,item))
       (b-tree-insert-aux ,tree-name ,item)))

This usage of the macro:

(b-tree-insert-macro tree-one foo)

expands into:

(IF (OR (NOT (BOUNDP 'TREE-ONE))
        (NULL TREE-ONE))
    (SETF TREE-ONE (MAKE-NODE FOO))
    (B-TREE-INSERT-AUX TREE-ONE FOO))

Notice that the expansion is the same regardless of the value of
the symbol TREE-ONE at macro-expansion time.  It is only when
this code is ultimately executed that it checks for the initial
state of the symbol.

One final note: when writing a macro it is usually helpful to
write the Lisp code that you want the macro to expand into first,
then write the macro that will produce that form.  That way you
separate out all the run-time evaluation issues (e.g. note that
in the OR clause above, TREE-ONE is quoted in one usage and not
in the second) from the macro-expansion-time ones.