From: Vladimir Zolotykh
Subject: define-compiler-macro
Date: 
Message-ID: <3C7BCFC8.F7CA0840@eurocom.od.ua>
I've tried example from CLHS (from section DEFINE-COMPILER-MACRO)

(defun square (x) (expt x 2))

(define-compiler-macro square (&whole form arg)
  (if (atom arg)
      `(expt ,arg 2)
    (case (car arg)
      (square (if (= (length arg) 2)
		  `(expt ,(nth 1 arg) 4)
		form))
      (expt (if (= (length arg) 3)
		(if (numberp (nth 2 arg))
		    `(expt ,(nth 1 arg) ,(* 2 (nth 2 arg)))
		  `(expt ,(nth 1 arg) (* 2 ,(nth 2 arg))))
	      form))
      (otherwise `(expt ,arg 2)))))

The call

  (funcall (compiler-macro-function 'square) '(square x) nil)

works as described but

  (funcall (compiler-macro-function 'square) '(funcall #'square x) nil)

doesn't work (I've tried ACL, CMUCL). 

I see the errors

- Error: macro funcall expects 1 argument, ...

- Invalid number of elements in:
    (#'SQUARE 3)
  to satisfy lambda-list:
    (&WHOLE FORM ARG)

In ACL and CMUCL respectively.

Would you mind to explain what is wrong there ?

-- 
Vladimir Zolotykh

From: Geoff Summerhayes
Subject: Re: define-compiler-macro
Date: 
Message-ID: <JtRe8.1721$kb.78034@news1.calgary.shaw.ca>
"Vladimir Zolotykh" <······@eurocom.od.ua> wrote in message
······················@eurocom.od.ua...
> I've tried example from CLHS (from section DEFINE-COMPILER-MACRO)
>
> (defun square (x) (expt x 2))
>
> (define-compiler-macro square (&whole form arg)
>   (if (atom arg)
>       `(expt ,arg 2)
>     (case (car arg)
>       (square (if (= (length arg) 2)
>   `(expt ,(nth 1 arg) 4)
> form))
>       (expt (if (= (length arg) 3)
> (if (numberp (nth 2 arg))
>     `(expt ,(nth 1 arg) ,(* 2 (nth 2 arg)))
>   `(expt ,(nth 1 arg) (* 2 ,(nth 2 arg))))
>       form))
>       (otherwise `(expt ,arg 2)))))
>
> The call
>
>   (funcall (compiler-macro-function 'square) '(square x) nil)
>
> works as described but
>
>   (funcall (compiler-macro-function 'square) '(funcall #'square x) nil)
>
> doesn't work (I've tried ACL, CMUCL).
>

Looks like a common bug.
Doesn't work in LW(4.2.0 Personal) either, but it does work in LW(4.1.20
Personal),
CLISP(2.27), and Corman(1.5).

Should the compiler macro also work with (apply #'func (list args))? Although it
isn't
spelled out in define-compiler-macro's entry an equivalence is implied under the
entry
for funcall. None of the implementations I've tried accept this.

----------
Geoff
From: Pekka P. Pirinen
Subject: Re: define-compiler-macro
Date: 
Message-ID: <uheo0i4mf.fsf@globalgraphics.com>
"Geoff Summerhayes" <·············@hNoOtSmPaAiMl.com> writes:
> Should the compiler macro also work with (apply #'func (list args))?
> Although it isn't spelled out in define-compiler-macro's entry an
> equivalence is implied under the entry for funcall. None of the
> implementations I've tried accept this.

That equivalence is in a Notes section, so it's not formally part of
the standard.  Nevertheless, it's a consequence of the definitions of
FUNCALL and APPLY, so a sufficiently clever compiler is a not
precluded from converting APPLY into FUNCALL and then invoking the
compiler macro.  But I don't think it's required, since the standard
doesn't say so.
-- 
Pekka P. Pirinen
Hell is other posters.
  - Nancy Lebovitz  (nancyL_universe.digex.net)
From: Geoff Summerhayes
Subject: Re: define-compiler-macro
Date: 
Message-ID: <A3Qf8.35303$kb.2094405@news1.calgary.shaw.ca>
"Pekka P. Pirinen" <···············@globalgraphics.com> wrote in message
··················@globalgraphics.com...
> "Geoff Summerhayes" <·············@hNoOtSmPaAiMl.com> writes:
> > Should the compiler macro also work with (apply #'func (list args))?
> > Although it isn't spelled out in define-compiler-macro's entry an
> > equivalence is implied under the entry for funcall. None of the
> > implementations I've tried accept this.
>
> That equivalence is in a Notes section, so it's not formally part of
> the standard.  Nevertheless, it's a consequence of the definitions of
> FUNCALL and APPLY, so a sufficiently clever compiler is a not
> precluded from converting APPLY into FUNCALL and then invoking the
> compiler macro.  But I don't think it's required, since the standard
> doesn't say so.

After reading the HS a bit more I realized it may cause problems in
compiler macros that don't expect a form with APPLY in it's car.

While I'm here, is there a proper or even a safe way to recurse
through forms in a compiler macro?

I wrote a simple addition function with a macro that
collected constant terms but the results weren't completely
to my liking.

Under one compiler for e.g.

(my_plus 1 2 3 (my-plus 4 5 6) 7 8)

becomes

(my-plus 21 15)

where I'd prefer 36, eliminating the call altogether in this case.


I've been thinking of using something along the lines of

(dolist (arg-element args)
  (cond
    ((and (consp arg-element)
        (compiler-macro-function (car arg-element)))
     (funcall (compiler-macro-function (car arg-element)) nil) arg-element))
     ...

with a bit more work to get the returned forms, figure out how to handle
the enviroment, and handle the funcall case if possible. I was wondering
if there were a function I could call so I could just something more
along the lines of...

(dolist (arg-element args)
  (when (listp arg-element)
     (setf arg-element (??? arg-element)))
  (cond ((numberp arg-element) ...

Is this a bad idea that only looks good in this context?

I know it has an excellent chance of slowing the compiler down
in most cases since it may repeat work that has already been done
but it makes sense to me that the macro should perform in this
fashion, optimizing the subforms before trying to optimize itself.

-----------

Geoff
From: Pekka P. Pirinen
Subject: Re: define-compiler-macro
Date: 
Message-ID: <ug03gmkla.fsf@globalgraphics.com>
"Geoff Summerhayes" <·············@hNoOtSmPaAiMl.com> writes:
> While I'm here, is there a proper or even a safe way to recurse
> through forms in a compiler macro?

You can't do as well as the compiler does (unless you hack into its
own internals), but you can process the argument list the way you need
here.

> [snip]
> with a bit more work to get the returned forms, figure out how to handle
> the enviroment, [...]

  (funcall (compiler-macro-function (car arg-element) env) arg-element env)

Theoretically, you should also respect NOTINLINE declarations here.
There isn't a portable way of doing that, so it might be safest just
to expand your own MY-PLUS.  Also, you should go through
*MACROEXPAND-HOOK* if you want to be a good citizen.

> I was wondering if there were a function I could call so I could
> just something more along the lines of...
> 
> (dolist (arg-element args)
>   (when (listp arg-element)
>      (setf arg-element (??? arg-element)))
>   (cond ((numberp arg-element) ...

There's no COMPILER-MACROEXPAND in the standard, but of course this
functionality must exist in the compiler.  The problem is that it
might be combined with other processing.  LW does have it as an
extension in the HCL package.  Undocumented, but with the obvious
semantics - i.e., it would do all that NOTINLINE and hook stuff for
you.  For portability, you could write your own under #-LispWorks.
-- 
Pekka P. Pirinen
If it's spam, it's a scam.  Don't do business with net abusers.
From: Geoff Summerhayes
Subject: Re: define-compiler-macro
Date: 
Message-ID: <9_rh8.34106$eb.1367789@news3.calgary.shaw.ca>
"Pekka P. Pirinen" <···············@globalgraphics.com> wrote in message
··················@globalgraphics.com...
>
> There's no COMPILER-MACROEXPAND in the standard, but of course this
> functionality must exist in the compiler.  The problem is that it
> might be combined with other processing.  LW does have it as an
> extension in the HCL package.  Undocumented, but with the obvious
> semantics - i.e., it would do all that NOTINLINE and hook stuff for
> you.  For portability, you could write your own under #-LispWorks.
> --

If I read the HS correctly, with these forms:
------------
(define-compiler-macro foo (&whole form &rest args &environment env)
        (format *trace-output* "~&macro called:~A~%" form)
        form)

(defun foo() (print 'hi))

(defun bar() (foo))

(defun baz() (declare (notinline foo)) (foo))
------------

(compile 'bar) should produce "macro called:(foo)"
and (compile 'baz) should not.

Is this correct? All the lisps I have tried print the line for both.

Geoff
From: Pekka P. Pirinen
Subject: Re: define-compiler-macro
Date: 
Message-ID: <uit81a765.fsf@globalgraphics.com>
"Geoff Summerhayes" <·············@hNoOtSmPaAiMl.com> writes:
> If I read the HS correctly, with these forms:
> ------------
> (define-compiler-macro foo (&whole form &rest args &environment env)
>         (format *trace-output* "~&macro called:~A~%" form)
>         form)
> 
> (defun foo() (print 'hi))
> 
> (defun bar() (foo))
> 
> (defun baz() (declare (notinline foo)) (foo))
> ------------
> 
> (compile 'bar) should produce "macro called:(foo)"
> and (compile 'baz) should not.
> 
> Is this correct? All the lisps I have tried print the line for both.

Yes, you're right.  Sadly, not even LWW gets it right (yes, that means
COMPILER-MACROEXPAND is not used by the compiler).  Sadly, because
some predecessors of the current LWW did, back when
COMPILER-MACROEXPAND was first written.  Unfortunately, that compiler
was otherwise lousy :-(.
-- 
Pekka P. Pirinen
"If you don't look after knowledge, it goes away."
  - Terry Pratchett, The Carpet People
From: Duane Rettig
Subject: Re: define-compiler-macro
Date: 
Message-ID: <43cz5mnyy.fsf@beta.franz.com>
···············@globalgraphics.com (Pekka P. Pirinen) writes:

> "Geoff Summerhayes" <·············@hNoOtSmPaAiMl.com> writes:
> > If I read the HS correctly, with these forms:
> > ------------
> > (define-compiler-macro foo (&whole form &rest args &environment env)
> >         (format *trace-output* "~&macro called:~A~%" form)
> >         form)
> > 
> > (defun foo() (print 'hi))
> > 
> > (defun bar() (foo))
> > 
> > (defun baz() (declare (notinline foo)) (foo))
> > ------------
> > 
> > (compile 'bar) should produce "macro called:(foo)"
> > and (compile 'baz) should not.
> > 
> > Is this correct? All the lisps I have tried print the line for both.
> 
> Yes, you're right.  Sadly, not even LWW gets it right (yes, that means
> COMPILER-MACROEXPAND is not used by the compiler).  Sadly, because
> some predecessors of the current LWW did, back when
> COMPILER-MACROEXPAND was first written.  Unfortunately, that compiler
> was otherwise lousy :-(.

I guess Geoff didn't try Allegro CL  :-)

CL-USER(1): (define-compiler-macro foo (&whole form &rest args &environment env)
        (format *trace-output* "~&macro called:~A~%" form)
        form)
FOO
CL-USER(2): (defun foo() (print 'hi))
FOO
CL-USER(3): (defun bar() (foo))
BAR
CL-USER(4): (defun baz() (declare (notinline foo)) (foo))
BAZ
CL-USER(5): (compile 'bar)
macro called:(FOO)
BAR
NIL
NIL
CL-USER(6): (compile 'baz)
BAZ
NIL
NIL
CL-USER(7): 

-- 
Duane Rettig          Franz Inc.            http://www.franz.com/ (www)
1995 University Ave Suite 275  Berkeley, CA 94704
Phone: (510) 548-3600; FAX: (510) 548-8253   ·····@Franz.COM (internet)
From: Thomas F. Burdick
Subject: Re: define-compiler-macro
Date: 
Message-ID: <xcv8z8xpehu.fsf@apocalypse.OCF.Berkeley.EDU>
Duane Rettig <·····@franz.com> writes:

> I guess Geoff didn't try Allegro CL  :-)

Nor CMUCL :-))

  *  (define-compiler-macro foo (&whole form &rest args &environment env)
       (format *trace-output* "~&macro called:~A~%" form)
       form)
  FOO
  * (defun foo() (print 'hi))
  FOO
  * (defun bar() (foo))
  BAR
  * (defun baz() (declare (notinline foo)) (foo))
  BAZ
  * (compile 'bar)
  In: LAMBDA (#:WHOLE-846 #:ENV-847)
    (LET* ((FORM #:WHOLE-846) (ARGS #) (ENV #:ENV-847))
      (FORMAT *TRACE-OUTPUT* "~&macro called:~A~%" FORM)
      FORM)
  Note: Variable ENV defined but never used.
  Note: Variable ARGS defined but never used.
  
  macro called:(FOO)
  Compiling LAMBDA NIL: 
  Compiling Top-Level Form: 
  BAR
  NIL
  NIL
  * (compile 'baz)
  Compiling LAMBDA NIL: 
  Compiling Top-Level Form: 
  
  BAZ
  NIL
  NIL
  * 

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Chris Riesbeck
Subject: Re: define-compiler-macro
Date: 
Message-ID: <riesbeck-C040EE.15000713032002@news.it.nwu.edu>
In article <···············@apocalypse.OCF.Berkeley.EDU>, 
···@apocalypse.OCF.Berkeley.EDU (Thomas F. Burdick) wrote:

>Duane Rettig <·····@franz.com> writes:
>
>> I guess Geoff didn't try Allegro CL  :-)
>
>Nor CMUCL :-))

Nor Macintosh CL, though there the effect shows up at DEFUN time
because that's when compilation happens.

? (defun bar() (foo))
macro called:(FOO)
BAR
? (defun baz() (declare (notinline foo)) (foo))
BAZ
From: Geoff Summerhayes
Subject: Re: define-compiler-macro
Date: 
Message-ID: <gPPj8.138376$kb.7601904@news1.calgary.shaw.ca>
"Chris Riesbeck" <········@cs.northwestern.edu> wrote in message
···································@news.it.nwu.edu...
> In article <···············@apocalypse.OCF.Berkeley.EDU>,
> ···@apocalypse.OCF.Berkeley.EDU (Thomas F. Burdick) wrote:
>
> >Duane Rettig <·····@franz.com> writes:
> >
> >> I guess Geoff didn't try Allegro CL  :-)
> >
> >Nor CMUCL :-))
>
> Nor Macintosh CL, though there the effect shows up at DEFUN time
> because that's when compilation happens.
>
> ? (defun bar() (foo))
> macro called:(FOO)
> BAR
> ? (defun baz() (declare (notinline foo)) (foo))
> BAZ

*SIGH*

No Mac in the house, maybe some day.

One hairy reconfig too many, deleted my Linux
partition, oops, no CMUCL.

Allegro, low on disk space around renewal time.
I do have some to spare now, hmmm...

---------

Geoff