From: Wolfgang Koehler
Subject: Help: apply for macros ???
Date: 
Message-ID: <2610@bigfoot.first.gmd.de>
I use CMU-Lisp and  allegro since more than one year.
But since some days I am stuck with a problem that might have a very
simple solution, but I'm not clever enough to get it.

consider you have a function f and want to call it from some other
function g with its &rest arguments.
Then you may use the apply function :

(defun f (p1 p2 ...)
  ...)

(defun g (&rest args)
 (apply #'f args))

My question :
 
Does there exist a similiar solution if "f" is a macro ???

Any help is greatly appreciated.


wolf

-- 
-------------------------------------------------------------------------
    ... always look on the bright side of life ... (Monty Python)
-------------------------------------------------------------------------
Wolfgang Koehler                               ····@first.gmd.de
GMD-FIRST an der TU Berlin              German National Research Centre 
Tel. (Berlin 030/049) 6704-2650              for Computer Science

From: Barry Margolin
Subject: Re: Help: apply for macros ???
Date: 
Message-ID: <1eh09vINNkc7@early-bird.think.com>
In article <····@bigfoot.first.gmd.de> ····@prosun.first.gmd.de (Wolfgang Koehler) writes:
>Does there exist a similiar solution if "f" is a macro ???

Since macros are source-to-source transformations, this generally doesn't
make sense to do.  If you wrote a function as a macro simply to speed it
up, you should use an inline function rather than a macro.

But if you really want to do it, you could write something kludgey like:

(defun g (&rest args)
  (eval `(f ,@args)))

Note that if the macro expansion results in any of its arguments being
evaluted, they'll be evaluated twice: once as part of the call to G and
later when the macroexpansion of F is executed.

Note: I'm *not* advocating this code, I think it's gross.  But if you have
a macro without a functional counterpart, you sometimes need to do it.
-- 
Barry Margolin
System Manager, Thinking Machines Corp.

······@think.com          {uunet,harvard}!think!barmar
From: Len Charest
Subject: Re: Help: apply for macros ???
Date: 
Message-ID: <1992Nov19.222419.4597@jpl-devvax.jpl.nasa.gov>
In article <····@bigfoot.first.gmd.de>, ····@prosun.first.gmd.de (Wolfgang Koehler) writes:
[ asks if it is possible to APPLY #'F where F is the name of a macro. ]

[[ This question and an appropriate answer should appear in the FAQ list. ]]

The short answer is no. Recall that #'F is shorthand for (FUNCTION F). However, F
names a macro--not a function or a LAMBDA-expression--so it is an error to
evaluate (FUNCTION F) (see CLtL2, p 116).* Furthermore, it is not permitted to
write (APPLY F ...) either since "the global function value of that symbol [F] is
used (but it is illegal for the symbol to be the name of a macro or special form."
(CLtL2, p 145)

It is quite possible to work around this problem:

Layered workaround: if you have the source code for the original macro then you
might want to rewrite it such that the macroexpansion is simply a call to a
function. The function may passed to APPLY. Here, the only job of the 
macroexpansion is to interpret, quote, rewrite or otherwise massage the arguments
of the macro. The philosophy behind this approach can be summed up as "If I can 
do it with a macro then I should also be able to do it with an equivalent function
call." Example:

(defun define-widget (name color viscosity)
  ...code to make a widget...)

;;; this macro simply quotes its args
(defmacro defwidget (name &key color viscosity)
  ;;there is an underlying function to do the work
  `(define-widget ',name ',color ',viscosity))

;;; macroexpansion reveals the equivalent function call:
(macroexpand-1 '(defwidget jello :color green)
=> (define-widget 'jello 'green nil)

Encapsulation workaround: you could simply define a function that calls your
macro. One pitfall here is that the macro call will not evaluate its arguments,
so if the macroexpansion quotes any arguments, an explicit call to EVAL
around those arguments will be necessary to get the encapsulation to perform 
correctly.

DEFSUBST workaround: you could redefine your macro as a DEFSUBST--that is, a
function that is proclaimed inline. An inline function *is* a function, so it may
be used with APPLY, but lexical calls to it will also be expanded inline by the
compiler.

#' workaround: you could redefine the #' reader to do whatever you want. I don't
recommend this approach. ;-)
..................................................
                                  Len Charest, Jr.
                 JPL Artificial Intelligence Group
                          ·······@aig.jpl.nasa.gov
From: Jeff Dalton
Subject: Re: Help: apply for macros ???
Date: 
Message-ID: <7953@skye.ed.ac.uk>
In article <····@bigfoot.first.gmd.de> ····@prosun.first.gmd.de (Wolfgang Koehler) writes:

>consider you have a function f and want to call it from some other
>function g with its &rest arguments.  Then you may use the apply function :
>
>(defun f (p1 p2 ...)
>  ...)
>
>(defun g (&rest args)
> (apply #'f args))
>
>My question :
> 
>Does there exist a similiar solution if "f" is a macro ???

This is a "frequently asked question", and the official answer is "no".
Questions that are essentially the same are

  Why can't I apply AND and OR?

  Why can't I use a macro with MAPCAR?

You should ask yourself what you want to accomplish by calling APPLY
on a macro.  What semantics do you think it should have?

In some Lisps (UCI, maybe Inter), a macro that worked like a function
(all args would be in evaluated positions in the expansion, etc) could
be applied.  But this meant -- in effect- getting the expansion and
then calling EVAL, and it didn't make sense for all macros.  We can
define this for CL:

   (defun apply-macro (mac-name arglist)
     (eval (macroexpand-1 
             (cons mac-name 
                   (mapcar #'(lambda (x) `',x) arglist)))))
So now

   > (apply-macro 'and '(t nil))
   nil

   > (apply-macro 'and '(t t t t))
   t

But also

   > (apply-macro 'and '((= 1 2) (= 2 3)))
   (= 2 3)

In short, APPLY-MACRO assumes ARGLIST contains values and not
expressions that compute values.  It will work for macros that
are "like functions" but not for macros such as DEFUN or COND.
Even AND and OR aren't really "like functions" because they
conditionally evaluate their arguments.

APPLY-MACRO constructs an expression such as (AND 'T 'NIL) [for the
1st example], and calls EVAL to get the expression evaluated.  That
sort of thing is usually a bad idea.  It's almost always better to
define a function that does what yuo want and then apply the function.

-- jd