From: Christophe Turle
Subject: MACROS : now i see the power !
Date: 
Message-ID: <c3phit$5lf$1@news.irisa.fr>
hello !


I program in lisp for some time now. And always the same question is recurring in my head : Why do they all say that macros are powerful ?
I understood the technical aspect of Macros. How to write them, debug them ... But why should i use them ? What is THE difference beetween
them and functions ???

1-  I see the non-evaluating part of the thing. it offers clean ways to build end user function interfaces. It is nicer to write (defclass Foo ...) than (defclass 'foo ...) for example. But it was not enough to speak about a true power. There must be something else ...

2-  The other things people spoke about are the ability to define new constructs. If you want a (with-output-to-browser ...) thing just build it and don't be stopped by the language designers. This is great because in other classical languages you can't do that ;-) But in fact, during my toy problems, i rarely code such new constructs. CL already contains the most useful ones for me. So there was something powerful but for  bigger projects where the application domain needs a tailored language, i thought...

3-  There was an other point : the compile vs run-time evaluation. All you can do at compile time is not to be done at run-time. It's the difference between interpreted language and embedded ones. All your application code is transformed into CL code. So at run-time it is faster to evaluate. For example, imagine you want to implement in CL the knowledge that appending 2 list evaluations is better done if you list all the elements of the 2 lists :

(macroexpand-1 '(append+ (list 'a 'b) (list 'b 'c)))
=> (list 'a 'b 'b 'c)

(macroexpand-1 '(append+ (list 'a 'b) (fct 'b)))
=> (append (list 'a 'b) (fct 'b))

When you will use append+ in your programs, it will optimize the code for you everywhere. It will run faster ;-)


here is a definition of such a macro :

(defmacro append+ ( L1 L2 )
  (if (and (consp L1)
	   (eql (first L1) 'list)
	   (consp L2)
	   (eql (first L2) 'list) )
      `(list ,@(append (cdr L1) (cdr L2)))
    `(append ,L1 ,L2) ))



So ok, it's cool. But during lots of months i didn't dig in that direction because i was not interested in gaining some milli-seconds.
My lisp programs are tools to help in my job. I describe problems and it helps me to write C++ or Java or Php or ... programs (So that
way i can find jobs and use lisp ;-) ). So time is not a priority for me ...


I was wrong ! gaining milli-seconds is not important, but gaining years is ! I just understood that using macros for optimizations can go
far beyond append+ tricks. How ? Give your system more and more meta-knowledge and it will do more and more of the work for you. And Macros
 seem to be the right tools to do that.

Example : You will gain lots of time teaching your system that (and (> x y) (<= x y)) is always false. This is meta-knowledge. And macros allow you to implement this knowledge. Imagine f is a very expensive function.

(macroexpand-1 '(and+ (<= (f) 1) (> (f) 1)))
=> nil ; so (f) will never be evaluated !!!

(macroexpand-1 '(and+ (<= (f) 1) (> (g) 1)))
=> (and (<= x 1) (> y 1))


code for and+ :

(defmacro and+ ( exp1 exp2 )
  (if (and (consp exp1)
	   (consp exp2)
	   (opposite-ops-ii (first exp1) (first exp2))
	   (equalp (cdr exp1) (cdr exp2)) )
      nil
    `(and ,exp1 ,exp2) ))

(defun opposite-ops-ii ( op1 op2 )
  (eql op2 (opposite-ops-io op1)) )

(defun opposite-ops-io ( op1 )
  (cond ((eql op1 '>) '<=)
	((eql op1 '<) '>=)
	((eql op1 '<=) '>)
	((eql op1 '>=) '<)
	((eql op1 '/=) '=)
	((eql op1 '=) '/=)
	(t :none) ) )


I didn't use macros before because i implemented all this meta-knowledge whenever i found it useful. Each time i saw an 'and' expression,
i looked for such verification. So time was wasted and like all humans sometimes i forgot to apply the knowledge.

The two examples are very simple. But i hope they help people to see the generality and power of macros that is behind. If a system with
lots of such meta-knowledge could be implemented it will be great (screamer is perhaps the nearest ?). Such improvements will lead us
toward declarativity. We will focus more on specifications than implementation details. But lots of work have to be done, so i will stop
talking and go back working ;-)


Thanks to all c.l.l. posters. Reading their posts really makes a difference.



(author "Christophe Turle" :nickname "ctu" )

From: Joe Marshall
Subject: Re: MACROS : now i see the power !
Date: 
Message-ID: <7jxb5yls.fsf@ccs.neu.edu>
Christophe Turle <······@nospam.fr> writes:

> hello !
>
>

> I program in lisp for some time now. And always the same question is
> recurring in my head : Why do they all say that macros are powerful?
> I understood the technical aspect of Macros.  How to write them,
> debug them ... But why should i use them? What is THE difference
> beetween them and functions ???

Variables abstract over values, functions abstract over behavior,
macros abstract over syntax.

> it offers clean ways to build end user function interfaces.

Just so.

> 2-  The other things people spoke about are the ability to define
> new constructs. If you want a (with-output-to-browser ...) thing
> just build it and don't be stopped by the language designers. This
> is great because in other classical languages you can't do that ;-) 

Exactly.

> But in fact, during my toy problems, i rarely code such new
> constructs. CL already contains the most useful ones for me. So
> there was something powerful but for  bigger projects where the
> application domain needs a tailored language, i thought... 

You may not *need* them all the time --- I don't often find a use for
displaced arrays or for modifying the readtable --- but that doesn't
mean they are useless.
From: Rob Warnock
Subject: Re: MACROS : now i see the power !
Date: 
Message-ID: <DHWdnZpxzYtO5_3d3czS-g@speakeasy.net>
Christophe Turle  <······@nospam.fr> wrote:
+---------------
| Example : You will gain lots of time teaching your system that (and (> x
| y) (<= x y)) is always false. This is meta-knowledge. And macros allow
| you to implement this knowledge. Imagine f is a very expensive function.
| 
| (macroexpand-1 '(and+ (<= (f) 1) (> (f) 1)))
| => nil ; so (f) will never be evaluated !!!
+---------------

CAREFUL!! Doing this sort of optimization correctly is harder
than it initially appears. What if F is stateful, or does I/O,
or is in *ANY* way not purely functional? Then you've broken
the semantics!!


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Kaz Kylheku
Subject: Re: MACROS : now i see the power !
Date: 
Message-ID: <cf333042.0403231234.d33c79c@posting.google.com>
Christophe Turle <······@nospam.fr> wrote in message news:<············@news.irisa.fr>...
> 3-  There was an other point : the compile vs run-time evaluation. All you
> can do at compile time is not to be done at run-time. It's the difference
> between interpreted language and embedded ones. All your application code is
> transformed into CL code. So at run-time it is faster to evaluate. For 
> example, imagine you want to implement in CL the knowledge that appending 2 
> list evaluations is better done if you list all the elements of the 2 lists :
> 
> (macroexpand-1 '(append+ (list 'a 'b) (list 'b 'c)))
> => (list 'a 'b 'b 'c)

This type of optimization is what compiler macros are for, not regular
macros.

The problem with APPEND+ is that it's not a function, which prevents
functional usage like:

    (mapcar #'append+ ...)

Compiler macros are smarter than this; they recognize forms that can
be optimized, but nicely get out of the way so you can use the
corresponding function normally.

Another optimization tool is inlining.

Don't use macros when an inline function will do the job!

Don't use regular macros when compiler macros will do the job!

> (macroexpand-1 '(append+ (list 'a 'b) (fct 'b)))
> => (append (list 'a 'b) (fct 'b))
> 
> When you will use append+ in your programs, it will optimize the code for you everywhere. It will run faster ;-)
> 
> 
> here is a definition of such a macro :
> 
> (defmacro append+ ( L1 L2 )
>   (if (and (consp L1)
> 	   (eql (first L1) 'list)
> 	   (consp L2)
> 	   (eql (first L2) 'list) )
>       `(list ,@(append (cdr L1) (cdr L2)))
>     `(append ,L1 ,L2) ))

Now define it like this:

 (declaim (inline append+))

 (defun append+ (l1 l2)
   (append l1 l2))

 (define-compiler-macro append+ (&whole original-form L1 L2)
   (if (and (consp L1)
            (eql (first L1) 'list)
            (consp L2)
            (eql (first L2) 'list))
      `(list ,@(append (cdr L1) (cdr L2)))
      original-form)))

Now APPEND+ is a function, and yet you have a recognizer that will
handle and translate your special case. Moreover, because APPEND+ has
been declaimed inline, calls to it which are not matched by the macro
can still be replaced by the equivalent APPEND (which, being a
standard function, can be further optimized by your Lisp system).

The real power of regular macros is to implement substantial new
languages within Lisp. For example, take a look at the LOOP macro.

  (loop for x below 10
        and (first last) in '((john smith) (betty wong))
        collecting (list first last x))

Try evaluating that and then use MACROEXPAND-1 to see how your Lisp
system translates it.
From: ctu
Subject: Re: MACROS : now i see the power !
Date: 
Message-ID: <4061b78b$0$290$626a14ce@news.free.fr>
> Compiler macros are smarter than this; they recognize forms that can
> be optimized, but nicely get out of the way so you can use the
> corresponding function normally.

Let me took my guy steele 2nd and look at compiler macros...

ctu
__________________________________________
Christophe Turle.
(format nil ···@~S.~S" 'cturle 'free 'fr)
From: Christophe Turle
Subject: Re: MACROS : now i see the power !
Date: 
Message-ID: <c3u9o3$kbv$1@news.irisa.fr>
> Compiler macros are smarter than this; they recognize forms that can
> be optimized, but nicely get out of the way so you can use the
> corresponding function normally.
> 
>  (declaim (inline append+))
> 
>  (defun append+ (l1 l2)
>    (append l1 l2))
> 
>  (define-compiler-macro append+ (&whole original-form L1 L2)
>    (if (and (consp L1)
>             (eql (first L1) 'list)
>             (consp L2)
>             (eql (first L2) 'list))
>       `(list :hello ,@(append (cdr L1) (cdr L2))) ; ctu : i added :hello to check results
>       original-form)))
> 
> Now APPEND+ is a function, and yet you have a recognizer that will
> handle and translate your special case.

ok after reading CLHS, here the results :

* (funcall (compiler-macro-function 'append+) '(append+ (list 'a 'b) (list 'b 'c)) nil)
(LIST :HELLO 'A 'B 'B 'C)

* (funcall (compiler-macro-function 'append+) '(append+ (list 'a 'b) '(b c)) nil)
(APPEND+ (LIST 'A 'B) '(B C))

It works. But unlike regular macros, the expansion is only done during compilation ( in fact it is just highly recommended ). The gain is
that now it is a function. So you can use mapcar ... But the use is not optimized since arguments are already evaluated !

* (mapcar #'append+ '((a b)) '((b c)))
((A B B C))

* (mapcar #'append+ (list (list 'a 'b)) (list (list 'b 'c)))
((A B B C)) ; no :hello !


Perahps, the solution is to have 'mapcar' as a macro too. but i have no clear idea of how to do that. I must think about it ....


@+

ctu.
From: Peter Seibel
Subject: Re: MACROS : now i see the power !
Date: 
Message-ID: <m3y8poom72.fsf@javamonkey.com>
Christophe Turle <······@nospam.fr> writes:

> It works. But unlike regular macros, the expansion is only done
> during compilation ( in fact it is just highly recommended ).

True.

> The gain is that now it is a function. So you can use mapcar ...

Also true.

> But the use is not optimized since arguments are already evaluated !

Huh? Why do you say this.

> * (mapcar #'append+ '((a b)) '((b c)))
> ((A B B C))
>
> * (mapcar #'append+ (list (list 'a 'b)) (list (list 'b 'c)))
> ((A B B C)) ; no :hello !

What makes you think this is being compiled? Try putting the same code
in a function and then compiling it.

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Christophe Turle
Subject: Re: MACROS : now i see the power !
Date: 
Message-ID: <c40qb6$nd$1@news.irisa.fr>
>>But the use is not optimized since arguments are already evaluated !
> 
> 
> Huh? Why do you say this.
> 
> 
>>* (mapcar #'append+ '((a b)) '((b c)))
>>((A B B C))
>>
>>* (mapcar #'append+ (list (list 'a 'b)) (list (list 'b 'c)))
>>((A B B C)) ; no :hello !
> 
> 
> What makes you think this is being compiled? Try putting the same code
> in a function and then compiling it.
> 
> -Peter
> 

i was so sure that compilation won't work that i forgot to compile it ;-) But anyway, the result is the same :

* (defun f () (mapcar #'append+ (list (list 'a 'b)) (list (list 'b 'c))))
F

* (f)
((A B B C)) ; no compilation ;)

* (compile 'f)
; Compiling LAMBDA NIL: 
; Compiling Top-Level Form: 

F
NIL
NIL

* (f)
((A B B C)) ; no :hello too !
 

ctu.
From: Peter Seibel
Subject: Re: MACROS : now i see the power !
Date: 
Message-ID: <m3d66zmvxb.fsf@javamonkey.com>
Christophe Turle <······@nospam.fr> writes:

>>>But the use is not optimized since arguments are already evaluated !
>> Huh? Why do you say this.
>>
>>>* (mapcar #'append+ '((a b)) '((b c)))
>>>((A B B C))
>>>
>>>* (mapcar #'append+ (list (list 'a 'b)) (list (list 'b 'c)))
>>>((A B B C)) ; no :hello !
>> What makes you think this is being compiled? Try putting the same
>> code
>> in a function and then compiling it.
>> -Peter
>>
>
> i was so sure that compilation won't work that i forgot to compile it ;-) But anyway, the result is the same :
>
> * (defun f () (mapcar #'append+ (list (list 'a 'b)) (list (list 'b 'c))))
> F
>
> * (f)
> ((A B B C)) ; no compilation ;)
>
> * (compile 'f)
> ; Compiling LAMBDA NIL: ; Compiling Top-Level Form:
>
> F
> NIL
> NIL
>
> * (f)
> ((A B B C)) ; no :hello too !

Okay, if I recall correctly, the point here was that you had a
compiler-macro on APPEND+. Did you try just a regular call to the
function as opposed to passing it to MAPCAR? It's not clear to me that
compiler macros are expected to be applied when you pass functions as
arguments.

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Christophe Turle
Subject: Re: MACROS : now i see the power !
Date: 
Message-ID: <c48o5o$di6$1@news.irisa.fr>
Peter Seibel wrote:
> Christophe Turle <······@nospam.fr> writes:
>
> (defun append+ (l1 l2)
>    (append l1 l2))
> 
> (define-compiler-macro append+ (&whole original-form L1 L2)
>   (if (and (consp L1)
>            (eql (first L1) 'list)
>            (consp L2)
>            (eql (first L2) 'list))
>      `(list :hello ,@(append (cdr L1) (cdr L2))) ; ctu : i added :hello to check results
>      original-form))) 
>
>>>>But the use is not optimized since arguments are already evaluated !
>>>
>>>Huh? Why do you say this.
>>>
>>>
>>>>* (mapcar #'append+ '((a b)) '((b c)))
>>>>((A B B C))
>>>>
>>>>* (mapcar #'append+ (list (list 'a 'b)) (list (list 'b 'c)))
>>>>((A B B C)) ; no :hello !
>>>
>>>What makes you think this is being compiled? Try putting the same
>>>code
>>>in a function and then compiling it.
>>>-Peter
>>>
>>
>>i was so sure that compilation won't work that i forgot to compile it ;-) But anyway, the result is the same :
>>
>>* (defun f () (mapcar #'append+ (list (list 'a 'b)) (list (list 'b 'c))))
>>F
>>
>>* (f)
>>((A B B C)) ; no compilation ;)
>>
>>* (compile 'f)
>>; Compiling LAMBDA NIL: ; Compiling Top-Level Form:
>>
>>F
>>NIL
>>NIL
>>
>>* (f)
>>((A B B C)) ; no :hello too !
> 
> 
> Okay, if I recall correctly, the point here was that you had a
> compiler-macro on APPEND+. Did you try just a regular call to the
> function as opposed to passing it to MAPCAR? It's not clear to me that
> compiler macros are expected to be applied when you pass functions as
> arguments.

* (defun g () (append+ (list (list 'a 'b)) (list (list 'b 'c))))
G

* (g)
((A B) (B C)) ; no :hello since not compiled.

* (compile 'g)

* (g)
(:HELLO (A B) (B C)) ; :hello after compilation.

The point was to show that even if compiler-macro produced functions instead of macros, we can't use the optimization when we call them with mapcar ... So this advantage over regular macros dissapears.

we even need to recompile when the macro definition changes :

(define-compiler-macro append+ (&whole original-form L1 L2)
  (if (and (consp L1)
           (eql (first L1) 'list)
           (consp L2)
           (eql (first L2) 'list))
     `(list :hello2 ,@(append (cdr L1) (cdr L2)))
     original-form))

* (g)
(:HELLO (A B) (B C)) ; old definition

* (compile 'g)
(:HELLO2 (A B) (B C)) ; new definition

not needed with regular macros :

* (defmacro appendm ( L1 L2 )
   (if (and (consp L1)
            (eql (first L1) 'list)
            (consp L2)
            (eql (first L2) 'list))
      `(list :hello ,@(append (cdr L1) (cdr L2))) ; *** note the :hello
      `(append ,@L1 ,@L2)))

* (appendm (list (list 'a 'b)) (list (list 'b 'c)))
(:HELLO (A B) (B C))

* (defmacro appendm ( L1 L2 )
   (if (and (consp L1)
            (eql (first L1) 'list)
            (consp L2)
            (eql (first L2) 'list))
      `(list :hello2 ,@(append (cdr L1) (cdr L2))) ; *** note the :hello2
      `(append ,@L1 ,@L2)))

* (appendm (list (list 'a 'b)) (list (list 'b 'c)))
(:HELLO2 (A B) (B C)) ; *** :hello2 without compile or recompile !


so advantages of compiler macros vs regular macros are not so clear ...


ctu.



 
From: Peter Seibel
Subject: Re: MACROS : now i see the power !
Date: 
Message-ID: <m3smfrha1z.fsf@javamonkey.com>
Christophe Turle <······@nospam.fr> writes:

> The point was to show that even if compiler-macro produced functions
> instead of macros, we can't use the optimization when we call them
> with mapcar ... So this advantage over regular macros dissapears.

Well the advantage doesn't disappear, just the opportunity to use the
optimization. Which makes sense--how can the compiler optimize this:

  (mapcar #'some-func a-list)

when it's not known at compile time what values will be in a-list. But
the point remains that a function with a compiler macro can still be
used as a function while a macro can not. Just because there are
situations where the compile-macro can't be used doesn't change
anything. Your macro also doesn't apply the optimaziton in certain
situations. (Actually your macro was broken in these situations but
fixing it like this:

  (defmacro appendm (l1 l2)
    (if (and (consp l1)
             (eql (first l1) 'list)
             (consp l2)
             (eql (first l2) 'list))
        `(list ,@(append (cdr l1) (cdr l2)))
        `(append l1 l2))) ;; you had (append ,@l1 ,@l2) which fails in the case below

when you do this:

  (let ((x (list 1 2))
        (y (list 3 4)))
     (appendm x y))

It can't take the optimized path because all the macro sees are the
two symbols X and Y.


> so advantages of compiler macros vs regular macros are not so clear
> ...

It might be better to think not in terms of "advantages" as "different
uses". FWIW, this kind of micro optimization via regular macros is
questionable style. However the idea of using macros that do
larger-scale code transformations to turn something concise and
expressive into a big pile of efficient code is quite good style.

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Patrick O'Donnell
Subject: Re: MACROS : now i see the power !
Date: 
Message-ID: <rt7jx050yz.fsf@ascent.com>
Peter Seibel <·····@javamonkey.com> writes:
> However the idea of using macros that do larger-scale code
> transformations to turn something concise and expressive into a big
> pile of efficient code is quite good style.

Or, even a big pile of not necessarily "efficient" code but "hard to
get right by hand" and "impossible to maintain correctly" repeated
patterns.

Just the other day, I wrote a macro to essentially do the following
kind of transformation.  I know which of these forms _I'd_ rather
maintain.  (Yes, it could be "optimized", but there was no need --
it's only called a few times in a session.  It only took a few minutes
to write and saved a couple hours of coding.  Spending those hours
again in optimizing the result unnecessarily would kinda miss the
point.)


(field-case (object (a b c d e f))
  ((a b c) ...do-one-thing...)
  ((a b e f) ...do-another-thing...)
  (() ...do-something-else...)
  (otherwise ...do-a-default-thing...))

into

(cond ((and (not (null (get-object-field-value object 'a t)))
            (not (null (get-object-field-value object 'b t)))
            (not (null (get-object-field-value object 'c t)))
            (null (get-object-field-value object 'd t))
            (null (get-object-field-value object 'e t))
            (null (get-object-field-value object 'f t)))
       (let ((a (get-object-field-value object 'a t))
             (b (get-object-field-value object 'b t))
             (c (get-object-field-value object 'c t)))
         ...do-one-thing...))
      ((and (not (null (get-object-field-value object 'a t)))
            (not (null (get-object-field-value object 'b t)))
            (null (get-object-field-value object 'c t))
            (null (get-object-field-value object 'd t))
            (not (null (get-object-field-value object 'e t)))
            (not (null (get-object-field-value object 'f t))))
       (let ((a (get-object-field-value object 'a t))
             (b (get-object-field-value object 'b t))
             (e (get-object-field-value object 'e t))
             (f (get-object-field-value object 'f t)))
         ...do-another-thing...))
      ((and (null (get-object-field-value object 'a t))
            (null (get-object-field-value object 'b t))
            (null (get-object-field-value object 'c t))
            (null (get-object-field-value object 'd t))
            (null (get-object-field-value object 'e t))
            (null (get-object-field-value object 'f t)))
       (let nil ...do-something-else...))
      (t (let ((a (get-object-field-value object 'a t))
               (b (get-object-field-value object 'b t))
               (c (get-object-field-value object 'c t))
               (d (get-object-field-value object 'd t))
               (e (get-object-field-value object 'e t))
               (f (get-object-field-value object 'f t)))
           ...do-a-default-thing...)))
From: Pascal Bourguignon
Subject: Re: MACROS : now i see the power !
Date: 
Message-ID: <87lllrbbw5.fsf@thalassa.informatimago.com>
Christophe Turle <······@nospam.fr> writes:

And you can add:

> (defmacro and+ ( exp1 exp2 )
>   (if (and (consp exp1)
>            (consp exp2)
>            (opposite-ops-ii (first exp1) (first exp2))
>            (equalp (cdr exp1) (cdr exp2)) )
      (progn
        (warn "(and+ %S %S) is always false!" exp1 exp2)
>       nil
        )
>     `(and ,exp1 ,exp2) ))

to be informed when you compile your program. 


-- 
__Pascal_Bourguignon__                     http://www.informatimago.com/
There is no worse tyranny than to force a man to pay for what he doesn't
want merely because you think it would be good for him.--Robert Heinlein
http://www.theadvocates.org/
From: Dirk Gerrits
Subject: Re: MACROS : now i see the power !
Date: 
Message-ID: <sA18c.96312$EI2.62805@amsnews05.chello.com>
Pascal Bourguignon wrote:
> Christophe Turle <······@nospam.fr> writes:
> 
> And you can add:
> 
> 
>>(defmacro and+ ( exp1 exp2 )
>>  (if (and (consp exp1)
>>           (consp exp2)
>>           (opposite-ops-ii (first exp1) (first exp2))
>>           (equalp (cdr exp1) (cdr exp2)) )
>       (progn
>         (warn "(and+ %S %S) is always false!" exp1 exp2)
>>      nil
>         )
>>    `(and ,exp1 ,exp2) ))
> 
> 
> to be informed when you compile your program. 

Please enlighten me, is the above okay, or should it be:

(defmacro and+ (exp1 exp2)
   (if (and (consp exp1)
            (consp exp2)
            (opposite-ops-ii (first exp1) (first exp2))
            (equalp (cdr exp1) (cdr exp2)))
       `(progn
          (eval-when (..something??..)
            (warn "(and+ %S %S) is always false!" exp1 exp2))
          nil)
       `(and ,exp1 ,exp2)))

I haven't really grasped EVAL-WHEN yet, but I hear macro's should expand 
into EVAL-WHEN rather than have side-effects of its own. Does that 
include warning messages?

Dirk Gerrits
From: Pascal Costanza
Subject: Re: MACROS : now i see the power !
Date: 
Message-ID: <c3qaf7$8u8$1@newsreader2.netcologne.de>
Dirk Gerrits wrote:

> Pascal Bourguignon wrote:
> 
>> Christophe Turle <······@nospam.fr> writes:
>>
>> And you can add:
>>
>>
>>> (defmacro and+ ( exp1 exp2 )
>>>  (if (and (consp exp1)
>>>           (consp exp2)
>>>           (opposite-ops-ii (first exp1) (first exp2))
>>>           (equalp (cdr exp1) (cdr exp2)) )
>>
>>       (progn
>>         (warn "(and+ %S %S) is always false!" exp1 exp2)
>>
>>>      nil
>>
>>         )
>>
>>>    `(and ,exp1 ,exp2) ))
>>
>>
>>
>> to be informed when you compile your program. 
> 
> 
> Please enlighten me, is the above okay, or should it be:
> 
> (defmacro and+ (exp1 exp2)
>   (if (and (consp exp1)
>            (consp exp2)
>            (opposite-ops-ii (first exp1) (first exp2))
>            (equalp (cdr exp1) (cdr exp2)))
>       `(progn
>          (eval-when (..something??..)
>            (warn "(and+ %S %S) is always false!" exp1 exp2))
>          nil)
>       `(and ,exp1 ,exp2)))
> 
> I haven't really grasped EVAL-WHEN yet, but I hear macro's should expand 
> into EVAL-WHEN rather than have side-effects of its own. Does that 
> include warning messages?

No, that rule is meant for different purposes. When your source code 
includes definitions that are supposed to be used by other macros at 
macro expansion time, then you use EVAL-WHEN. You can only make 
EVAL-WHEN have a compile-time effect for toplevel forms. This means that

(eval-when (:compile-toplevel)
   (defun f (...) ...))

...will make f available for other macros but...

(let ((some-binding))
   (eval-when (:compile-toplevel)
     (defun f (...) ...)))

...won't because here f depends on the lexical environment in which it 
is defined, and that lexical environment is by definition only available 
at run time.

If you provide your own DEF-style macros you should not work against 
theses notions by doing the following:

(defmacro defmystuff (...)
   (make-it-available)
   `(make-it-available))

...but instead do the following:

(defmacro defmystuff (...)
   `(eval-when (:compile-toplevel ...)
      (make-it-available)))

...because only then the following will work as expected.

(let ((some-binding))
   (defmystuff ...))

Checking for errors and warnings in the use of a macro can and should 
lead to issuing respective messages in the macro code itself because the 
programmer should be notified no matter whether the macro is used in a 
toplevel position or not.


Pascal

-- 
1st European Lisp and Scheme Workshop
June 13 - Oslo, Norway - co-located with ECOOP 2004
http://www.cs.uni-bonn.de/~costanza/lisp-ecoop/
From: Kalle Olavi Niemitalo
Subject: Re: MACROS : now i see the power !
Date: 
Message-ID: <87u10f44wh.fsf@Astalo.kon.iki.fi>
Christophe Turle <······@nospam.fr> writes:

> (macroexpand-1 '(append+ (list 'a 'b) (fct 'b)))
> => (append (list 'a 'b) (fct 'b))

The expansion could be (list* 'a 'b (fct 'b)).  Also, I think it
would be better to implement APPEND+ as a compiler macro so that
one could FuNCALL and APPLY it.

  (declaim (inline append+))
  (defun append+ (&rest lists)
    (apply #'append lists))
  (define-compiler-macro append+ (&whole form &rest lists)
    ...)

I wonder if one could replace the DEFUN with
  (setf (symbol-function 'append+) #'append)
and speed up FUNCALLs a little.  Or would that prevent
compilers from inlining (append+ ...) calls?
From: André Thieme
Subject: PHP (was: MACROS : now i see the power !)
Date: 
Message-ID: <c3qel3$860$1@ulric.tng.de>
Christophe Turle wrote:
> So ok, it's cool. But during lots of months i didn't dig in that 
> direction because i was not interested in gaining some milli-seconds.
> My lisp programs are tools to help in my job. I describe problems and it 
> helps me to write C++ or Java or Php or ... programs (So that
> way i can find jobs and use lisp ;-) ). So time is not a priority for me 
> ...

Do you mean you have tools or know about tools, who translate Lisp
programs into php?
This would be very funny, because I have to do a good amount of php at
work and I don't think I can't convince the project manager to switch
over to Lisp (cause already several hundred php scripts are working in
this project and the other programmers don't know about Lisp).

But with your trick I could probably write at least some of the scripts
in Lisp and let them be translated into php.

Anyone who can provide some info?


Andr�
--
From: Christophe Turle
Subject: Re: PHP
Date: 
Message-ID: <c3robc$n95$1@news.irisa.fr>
> Do you mean you have tools or know about tools, who translate Lisp
> programs into php?
> This would be very funny, because I have to do a good amount of php at
> work and I don't think I can't convince the project manager to switch
> over to Lisp (cause already several hundred php scripts are working in
> this project and the other programmers don't know about Lisp).
> 
> But with your trick I could probably write at least some of the scripts
> in Lisp and let them be translated into php.

The trick is no more than meta-programming. I try to define some application-related knowledge using lisp. Then my lisp functions write some target code. The goal is not to have a conversion program. The goal is to have a program which have knowledge about different language. it is a long term goal and i'm far from having showable results. The only general thing i have is a tool to include meta-code into source files.

here's an example :


; file generated by an idl to C++ compiler

...

// begin-asgard-code (snc-method-definitions-of-corba-object "PC-GraphEH" )


; all the code below is generated automatically from the evaluation of the expression : '(snc-method-definitions-of-corba-object "PC-GraphEH" )'

void CorbaObject::added_ERport (
  const char * ERportId
)
ACE_THROW_SPEC ( ( CORBA::SystemException ) )
{
  cout << "--> GraphEH::added_ERport(" << " ERportId='" << ERportId << "'" << " )" << endl ;

  NodeId lv_ERportId = static_cast< NodeId > ( ERportId ) ;

  // begin-user-code (app-code (corba-c++:c++-method (FIND-CORBA-SERVICE (FIND-CORBA-OBJECT "PC-GraphEH") :NAME "added_ERport")))

  ; we can't generate all code automatically. begin-user-code allows us to insert user code.
  ; all code here is 'setf' to the expression
  ; (app-code (corba-c++:c++-method (FIND-CORBA-SERVICE (FIND-CORBA-OBJECT "PC-GraphEH") :NAME "added_ERport")))
  ; which should be used at this space during the generation process.

  mr_msn.add_ERport( lv_ERportId ) ;
  // end-user-code
}

...

// end-asgard-code
...
; end-of -file



; file snc-corba.lisp

...

;;; surely i can generate this from the idl file using clorb.

(def-idl-interface
  :name "GraphEH"
  :operations ( (:name "added_ERport" :args ((:type NodeId  :name "ERportId")))
                 ... ))

...

(def-corba-component :abbrev    "PC"  :name "pathControler")
(def-corba-object    :component "PC"  :idl-interface "GraphEH" )

...
;end-of-file


This way, all codes in any source file, i can generate automatically is. I just need to (update-files).


(author "Christophe Turle" :nickname "ctu")
From: Tim Daly Jr.
Subject: Re: PHP (was: MACROS : now i see the power !)
Date: 
Message-ID: <87brmlgt7o.fsf@hummer.intern>
Andr� Thieme <······································@justmail.de> writes:
...
> This would be very funny, because I have to do a good amount of php at
> work and I don't think I can't convince the project manager to switch
> over to Lisp (cause already several hundred php scripts are working in
> this project and the other programmers don't know about Lisp).
> 
> But with your trick I could probably write at least some of the scripts
> in Lisp and let them be translated into php.
> 
> Anyone who can provide some info?

I know where you could get a PHP compiler that lets you mix PHP and
Scheme... :)

-- 
-Tim

Check out the new PHP compiler:  www.roadsend.com
From: ····························@t-online.de
Subject: Re: PHP (was: MACROS : now i see the power !)
Date: 
Message-ID: <y59y8pp19y9.fsf@edoras.trapp.net>
No cookies --> no play with me;
no play with me --> no play with it

Regards
-- tom�s (@······················@)
From: Tim Daly Jr.
Subject: Re: PHP (was: MACROS : now i see the power !)
Date: 
Message-ID: <874qsdgpcp.fsf@hummer.intern>
····························@t-online.de writes:

> No cookies --> no play with me;
> no play with me --> no play with it

Wow.  That was like... beautiful, man.

-- 
-Tim

Check out the new PHP compiler:  www.roadsend.com
From: André Thieme
Subject: Re: PHP
Date: 
Message-ID: <c4042v$4hg$2@ulric.tng.de>
Tim Daly Jr. wrote:

> Andr� Thieme <······································@justmail.de> writes:
> ...
> 
>>This would be very funny, because I have to do a good amount of php at
>>work and I don't think I can't convince the project manager to switch
>>over to Lisp (cause already several hundred php scripts are working in
>>this project and the other programmers don't know about Lisp).
>>
>>But with your trick I could probably write at least some of the scripts
>>in Lisp and let them be translated into php.
>>
>>Anyone who can provide some info?
> 
> 
> I know where you could get a PHP compiler that lets you mix PHP and
> Scheme... :)

Ok, I think this is a game and I am now in the position to ask you the
question for which you are waiting. As a fair player I will do exactly
this:

Hey Tim, man, I know that you know where I could get a PHP compiler that
lets me mix PHP and Scheme... could you please be so nice and tell me
more about it?

*cheers*


Andr�
--
From: Tim Daly Jr.
Subject: Re: PHP
Date: 
Message-ID: <87u10beo3x.fsf@hummer.intern>
Andr� Thieme <······································@justmail.de> writes:

> Tim Daly Jr. wrote:
>
> > I know where you could get a PHP compiler that lets you mix PHP and
> > Scheme... :)
> 
> Ok, I think this is a game and I am now in the position to ask you the
> question for which you are waiting. As a fair player I will do exactly
> this:
> 
> Hey Tim, man, I know that you know where I could get a PHP compiler that
> lets me mix PHP and Scheme... could you please be so nice and tell me
> more about it?

No, that wasn't my intention at all.  I'm just a code monkey.  Besides
which, there's no reason to spam this forum with stuff about a PHP
compiler written in Scheme, neither of which is CL.  I was rather
hoping you'd follow the link in my signature, or communicate with me
directly, if you're interested.

I followed up to the newsgroup just in case there are more Lispers out
there that find themselves wishing they could write code in something
more Lispy, and still be considered useful at their PHP-oriented
dayjobs.  The compiler, as well as the runtime and the libraries, is
written in Bigloo Scheme.  However, we have not yet publicized the
information necessary to integrate your own Scheme code with PHP.  We
would only do that if anybody shows any interest.  So if you're
interested, please let us know. :)

ObLisp : Although Bigloo is a Scheme, it is an extremely practical
one.  The aspects of the language that were most useful were also the
most Common-Lispy -- define-macro (defmacro), and generic functions.
Also explicit typing for speed (Bigloo lets you decorate symbols with
types in lieu of CL's declarations and checks).  Dynamic binding
(essentially special variables) has been terribly useful.  For
performance reasons, continuations are disabled.  Instead, we use
dynamic non-local exits (Bigloo's bind-exit).  

Jeez, that list got longer than I expected.

-- 
-Tim

Check out the new PHP compiler:  www.roadsend.com
From: André Thieme
Subject: Re: PHP
Date: 
Message-ID: <c47fhu$7m3$1@ulric.tng.de>
Tim Daly Jr. wrote:

> No, that wasn't my intention at all.  I'm just a code monkey.  Besides
> which, there's no reason to spam this forum with stuff about a PHP
> compiler written in Scheme, neither of which is CL.  I was rather
> hoping you'd follow the link in my signature, or communicate with me
> directly, if you're interested.

I am very well trained in ignoring signatures.
Thanks for the link and explanations.


Andr�
--