From: Brendan Nolan
Subject: Query: Common Lisp prevents mapping of macros.
Date: 
Message-ID: <33.254dd6ce@ccvax.ucd.ie>
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.

Could someone clarify why this is the case?

Thanks in advance.

Brendan.

From: Bruce Krulwich
Subject: Re: Query: Common Lisp prevents mapping of macros.
Date: 
Message-ID: <1457@accuvax.nwu.edu>
In article <···········@ccvax.ucd.ie>, ······@ccvax (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.

The reason why macros cannot be used as functional arguments is that they are
not intended to necessarily exist at run-time.  The idea (as I understand it
and have always seen it) is that all macro calls are expanded at compile-time
and their expansions are then compiled.  That's the reason that they're
useful, that they do compile-time computation.

There are two ways to achieve use of macros as functional arguments.  The
first is to write a dummy function (LAMBDA (X Y) (OR X Y)) and use it for
mapping, funcalling, etc.  This way the function you make contains the macro
expansion of OR but it in and of itself an explicit function.  The second way
is for the LISP system you are using to do it for you, ie, to construct dummy
functions for any macros or special forms that you use as functional
arguments.  For example, I believe that Allegro CL does this for alot of the
basic functions in the language.


Bruce

 
From: Eliot Handelman
Subject: Re: Query: Common Lisp prevents mapping of macros.
Date: 
Message-ID: <11218@phoenix.Princeton.EDU>
;>                 ... mapping OR across a list of forms with 
;>FUNCALL to find the first one which returns non-nil without
;>having to evaluate the remainder.


(macroexpand '(OR X Y Z))

==>

(let ((gen1 x))
  (if gen1 gen1
      (let ((gen1 y))
	(if gen1 gen1
	    z))))

Seems to do exactly what you want.
From: Barry Margolin
Subject: Re: Query: Common Lisp prevents mapping of macros.
Date: 
Message-ID: <31339@news.Think.COM>
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.

Someone else already mentioned that the macros need not exist at runtime,
if you've compiled your program.  The naive response to that is, "well,
what if I make sure the macros are available at runtime?"

The real answer is that macros are program-transformation functions, not
functions on "normal" data.  This is what CLtL is talking about when it
says that the form no longer exists.

For instance, when you evaluate or compile the form

	(or <form1> <form2> <form3>)

the macro is given the above list as an argument, and it returns something
like:

	(let ((temp1 <form1>))
	  (if temp1
	      temp1
              (let ((temp2 <form2>))
		(if temp2
		    temp2
		    <form3>))))

and then this form is evaluated or compiled.

So, since the argument and value of a macro are lisp programs, it doesn't
make sense to try to funcall or apply the macro to ordinary data.

If that doesn't clear it up, here's another example that may help.  One of
the first macros most of us ever learn is PUSH.  Here's a simple definition
of PUSH (it only handles normal variables, not generalized references):

(defmacro push (value variable)
  `(setq ,variable (cons ,value ,variable)))

Then suppose you wanted to funcall this, e.g.

(setq my-list '(a b c))
(funcall #'push 3 my-list)

Now think of the reason that push was written as a macro rather than as a
function: it needs to be able to SETQ the variable.  However, when ordinary
functions are called, all their arguments are evaluated, so MY-LIST is
evaluated; FUNCALL gets the arguments #<FUNCTION PUSH>, 3, and (A B C).
How could FUNCALL then pass to PUSH the information necessary to update the
MY-LIST variable?

Going back to OR, remember that part of OR's job is to stop evaluating
forms once it encounters one that returns non-NIL.  If you write

(funcall #'or <form1> <form2> <form3>)

the forms will ALL be evaluated normally, because FUNCALL is an ordinary
function.  Supposing <form1> is true, how can OR arrange for <form2> and
<form3> not to be evaluated, when it doesn't get control until after they
have been evaluated?
Barry Margolin, Thinking Machines Corp.

······@think.com
{uunet,harvard}!think!barmar
From: Cesar Quiroz
Subject: Re: Query: Common Lisp prevents mapping of macros.
Date: 
Message-ID: <1989Nov2.022423.3880@cs.rochester.edu>
By now it should be clear _why_ macros cannot be funcalled, mapcared,
etc...  It may, however, remain to say _what_ to do when you feel the
itch to map `or' over some poor unsuspecting list.  [Experts may quit
here.]

The problem:

······@ccvax.ucd.ie (Brendan Nolan)
| In COMMON LISP, macros can not be used as functional arguments to
| such functions as apply, funcall, or mapping functions. ...  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. ...

The solution:

Even neater constructs!  Here come some classical examples:

DON'Ts                              DOs

(funcall #'or                       (some #'evenp list)
  (mapcar #'evenp list))            

(funcall #'and                      (every #'evenp list)
  (mapcar #'evenp list))            


The Don'ts above are real DON'Ts.  There are also cases where clumsy
(but legal) constructs can be replaced by more perspicuous ones,
like `(apply #'append (mapcar #'pred list))', that often reduces to
`(mapcan #'(lambda (thing) (if (pred thing) (list thing))) list)',
or to `(remove-if-not #'pred list)'.

The programmer inexperienced in Common Lisp (even if experienced in
other varieties of Lisp) does well in looking up the Sequences
chapter of the book%.  Some of those functions come handy very
often, and will eliminate the itches mentioned above nearly always.

(HOWEVER, the sequence functions are generic, and so may be slower
than some more specific counterpart.  The implementation I use more
often has a slow remove-if-not, in comparison with the mapcan idiom,
so I almost never use the clearer version.  Maybe I should fix the
compiler, and be simultaneously clear and happy :-)

Cesar

% *That* book, indeed

-- 
                                      Cesar Augusto Quiroz Gonzalez
                                      Department of Computer Science
                                      University of Rochester
                                      Rochester,  NY 14627