From: Larry Baum
Subject: Re: Query: Common Lisp prevents mapping of macros.
Date: 
Message-ID: <16520@bcsaic.UUCP>
In article <···········@ccvax.ucd.ie; ······@ccvax.ucd.ie (Brendan Nolan) writes:
;In COMMON LISP, macros can not be used as functional 
;arguments to such functions as apply, funcall, or mapping 
;functions. Steele says this is because, in such situations, 
;the list representing the "original macro call" does not 
;exist, and cannot exist, because in some sense the arguments 
;have already been evaluated.
;
;I'm not sure that I fully understand this but it seems 
;an inconvenience which needs not be in the design. It prevents 
;neat constructs like mapping OR across a list of forms with 
;FUNCALL to find the first one which returns non-nil without
;having to evaluate the remainder.
;
I'll let someone else answer the general case question, but for your
example you can easily do:

(apply #'or list-of-forms)



-- 
Larry Baum
Advanced Technology Center              
Boeing Computer Services     uucp:       uw-beaver!bcsaic!lbaum
(206) 865-3232               internet:   ·····@atc.boeing.com       

From: Larry Baum
Subject: Re: Query: Common Lisp prevents mapping of macros.
Date: 
Message-ID: <16631@bcsaic.UUCP>
In article <·····@bcsaic.UUCP> I stupidly wrote:
>I'll let someone else answer the general case question, but for your
>example you can easily do:
>
>(apply #'or list-of-forms)

I hereby retract this ridiculous code:

 1) You can't apply a macro, so this is illegal
 2) Even if it were legal it would be wrong since with OR we don't want each form
evaluated unless the preceeding ones return nil.

Moral: Never try to answer such questions when you are sick and have had little
sleep.
-- 
Larry Baum
Advanced Technology Center              
Boeing Computer Services     uucp:       uw-beaver!bcsaic!lbaum
(206) 865-3232               internet:   ·····@atc.boeing.com       
From: Jeff Dalton
Subject: Re: Query: Common Lisp prevents mapping of macros.
Date: 
Message-ID: <1362@skye.ed.ac.uk>
In article <·····@bcsaic.UUCP> ·····@bcsaic.UUCP (Larry Baum) writes:
>In article <·····@bcsaic.UUCP> I stupidly wrote:
>>I'll let someone else answer the general case question, but for your
>>example you can easily do:
>>
>>(apply #'or list-of-forms)
>
>I hereby retract this ridiculous code:
>
> 1) You can't apply a macro, so this is illegal
> 2) Even if it were legal it would be wrong since with OR we don't
>    want each form evaluated unless the preceding ones return nil.

A good paper is (still) Kent Pitman's "Special Forms in Lisp" in
the Proceedings of the 1980 Lisp Conference.  It explains some of
the background that led to Common Lisp having macros but not user-
defined special forms of the FEXPR and NLAMBDA sort.  It's also
useful for understanding macros in general.

Now to the question at hand...

Several people have sent messages that give a good explanation of 
why macros cannot be mapped.  I want to explain why sometimes they
might be.

I think anyone who wants to map macros (or use them as functions in
other ways) should ask themselves what semantics they want to have.
What is mapping COND supposed to do, for example?  How about just
FUNCALLing COND?  Are we supposed to write something like

  (funcall #'cond '((test1 x) (process1 x)) '((test2 x) (process2 x)))

or what?  What is the result supposed to be?  Normally macros just
compute an expansion.  That suggests that the result of the call
above should be something like

  (if (test1 x) (process1 x) (if (test2 x) (process2 x) nil))

In Franz Lisp, macros can be applied, and the result is the expansion.
However, this is presumably not the sort of semantics people want when
they think of mapping OR.

The point about arguments already being evaluated is related.
For functions (f arg...) and (FUNCALL #'f arg...) are equivalent.
Macros, however, normally work on the "source code" of their
arguments, not on the values that source code might produce if
it was interpreted as expressions.  In (m arg...) it's the args, not
the values of the args, that the macro normally precesses.  But on the
FUNCALL side, the args will already have been evaluated by the time
the macro gets to see them.  So the two expressions (one using
FUNCALL, the other not) will not be equivalent for macros.  Whatever
semantics we give to FUNCALL of a macro, it won't be exactly the
same semantics we give to FUNCALL of functions.

Suppose, however, that, given some values, we could reconstruct macro
arguments that the macro could process in a reasonable way.  There's
no good way to get from the value A to the expression (CAR '(A B C)).
How would we know it was (CAR '(A B C)) and not (CADR '(B A C)), for
example?  But some macros don't process their arguments in a very
interesting way and so may not care all that much what expression we
reconstruct.  In some cases, all that matters is that the expression
have the right value.  Then we may as well turn a value, v, into the
expression (QUOTE v).  In what cases will this work?

Well, it won't work very well for macros like DEFUN and COND, but
some macros are a lot more like functions.  Suppose a macro has
the following properties:

  (1) All the macro's arguments must be valid as expressions.
      This is true for AND, and OR, for example, but not for
      COND and DEFUN.  

  (2) The macro treats the arguments as expressions in a function-like
      way.

One problem is that it's not entirely clear what should count as (2).
In a function call, the argument expressions are all evaluated once,
but in OR, for example, they are evaluated conditionally.  However,
some macros are meant to have the semantics of in-line functions; and
they should definitely count.  Here is such a macro:

  (defun kar (x) `(car ,x))

Sometimes people write such macros to avoid the overhead of a function
call.  But then they can't use the macro with mapping functions or APPLY.
Some Lisps let you define a name as both a macro and a function to get
around this very problem.  But such a macro _could_ be called in a
reasonable way by a function like this:

  (defun call-macro (macro-name &rest args)
    (eval (cons macro-name
                (mapcar #'(lambda (arg) `',arg)
                        args))))

We know that (KAR '(APPLE PIE)) evals to APPLE in two steps.  First,
it's expanded to get (CAR '(APPLE PIE)); then CAR's called to return
APPLE.

(CALL-MACRO 'KAR '(APPLE PIE)) causes CALL-MACRO to be called with two
values, KAR and (APPLE PIE).  CALL-MACRO then constructs the macro
call (KAR '(APPLE PIE)).  Here, we've got our original expression back
again, but CALL-MACRO doesn't know what the original was; it would do
the same for any expression whose value was (APPLE PIE).  For example,
(CALL-MACRO 'KAR (LIST 'APPLE 'PIE)) would also cause CALL-MACRO to
construct (KAR '(APPLE PIE)).  In any case, we now have a macro call
that can be evaluated.  And it's evaluated just as before: first it's
expanded to get (CAR '(APPLE PIE)), then CAR is called.

We can use the same technique to call macros like OR.  Of course,
OR doesn't get to conditionally evaluated the arguments to CALL-MACRO,
but sometimes we wouldn't care.

I believe UCI Lisp used to have a version of APPLY, called #APPLY,
that could apply macros in a manner similar to this.  But maybe it
worked a different way.  I no longer have access to a UCI Lisp to
check.

Jeff Dalton,                      JANET: ········@uk.ac.ed             
AI Applications Institute,        ARPA:  ·················@nsfnet-relay.ac.uk
Edinburgh University.             UUCP:  ...!ukc!ed.ac.uk!J.Dalton