From: Martin Raspaud
Subject: About a macro
Date: 
Message-ID: <c0im9q$vcd$1@news-reader1.wanadoo.fr>
Hi all,

I'm quite new to lisp, but I started writing a bit of code... Things are 
getting on well (at least, it's working) but I didn't use any macro 
yet... I'm reading Paul Graham's "On Lisp" which I find great, but I'm 
still not very at ease with macros. He writes that macros are made to 
transform expressions... So I thought "let's write a small macro for my 
needs" : I would like to extend classic arithmetic operations to 
sequences... for example
(my-macro 'list (+ '(1 2 3) #(3 2 1))) would return (4 4 4), but also
(my-macro 'vector (+ '(1 2 3) 5)) would return #(6 7 8) and
(my-macro 'list (+ '(1 2 3) (* 5 '(1 2 3)))) would return (6 12 18)

so, take Paul Graham's method, I would write what I'll have to type :
* (my-macro 'list (+ number1 sequence2 (* sequence3 number4)))

and that would expand to

(map 'list #'(lambda (x2 x3) (+ number1 x2 (* x3 number4))) sequence2 
sequence3)

but honestly I really don't know how to write the macro after that... 
The most mysterious part for me is how to transform the sequences in the 
original expression into variables for the lambda function...

Could anyone enlighten me ?

Thanks anyway

Martin

From: Espen Vestre
Subject: Re: About a macro
Date: 
Message-ID: <kwr7wzxbqo.fsf@merced.netfonds.no>
Martin Raspaud <··············@wanadoo.fr> writes:

> I'm quite new to lisp, but I started writing a bit of code... Things
> are getting on well (at least, it's working) but I didn't use any
> macro yet... I'm reading Paul Graham's "On Lisp" which I find great,
> but I'm still not very at ease with macros. 

Hmm, are you sure you're ready for "On Lisp" yet? Most lisp programmers
(myself included) dive into macros a little to early.

> made to transform expressions... So I thought "let's write a small
> macro for my needs" : I would like to extend classic arithmetic
> operations to sequences... for example
> (my-macro 'list (+ '(1 2 3) #(3 2 1))) would return (4 4 4), but also
> (my-macro 'vector (+ '(1 2 3) 5)) would return #(6 7 8) and
> (my-macro 'list (+ '(1 2 3) (* 5 '(1 2 3)))) would return (6 12 18)

I guess the only point of using a macro here would be to replace
the + and * with something else? I don't think that's a very good
idea, especially since you have operators that almost match what
you want to do:

CL-USER 2 > (map 'list #'+ #(1 2 3) '(10 20 30))
(11 22 33)

Here's a little idea: Why not go for something completely different?
You can use a generic function instead to extend the behaviour of
map the way you want:

CL-USER 5 > (defmethod my-map (result-type operator (x sequence)(y sequence))
              (map result-type operator x y))
#<STANDARD-METHOD MY-MAP NIL (T T SEQUENCE SEQUENCE) 206F4864>

CL-USER 6 > (defmethod my-map (result-type operator (x number) (y sequence))
              (map result-type (lambda (y-elt)(funcall operator x y-elt)) y))
#<STANDARD-METHOD MY-MAP NIL (T T NUMBER SEQUENCE) 206EAF64>

CL-USER 7 > (my-map 'list #'* 5 '(1 2 3 4))
(5 10 15 20)

CL-USER 8 > (my-map 'list #'* '(5 10 20 30) '(1 2 3 4))
(5 20 60 120)

-- 
  (espen)
From: Martin Raspaud
Subject: Re: About a macro
Date: 
Message-ID: <c0ipo9$eru$1@news-reader5.wanadoo.fr>
Espen Vestre a �crit :
> Martin Raspaud <··············@wanadoo.fr> writes:
> 
> 
>>I'm quite new to lisp, but I started writing a bit of code... Things
>>are getting on well (at least, it's working) but I didn't use any
>>macro yet... I'm reading Paul Graham's "On Lisp" which I find great,
>>but I'm still not very at ease with macros. 
> 
> 
> Hmm, are you sure you're ready for "On Lisp" yet? Most lisp programmers
> (myself included) dive into macros a little to early.

Yep maybe, but better soon than never ;-)

>>made to transform expressions... So I thought "let's write a small
>>macro for my needs" : I would like to extend classic arithmetic
>>operations to sequences... for example
>>(my-macro 'list (+ '(1 2 3) #(3 2 1))) would return (4 4 4), but also
>>(my-macro 'vector (+ '(1 2 3) 5)) would return #(6 7 8) and
>>(my-macro 'list (+ '(1 2 3) (* 5 '(1 2 3)))) would return (6 12 18)
> 
> 
> I guess the only point of using a macro here would be to replace
> the + and * with something else? I don't think that's a very good
> idea, especially since you have operators that almost match what
> you want to do:
> 
> CL-USER 2 > (map 'list #'+ #(1 2 3) '(10 20 30))
> (11 22 33)
> 
> Here's a little idea: Why not go for something completely different?
> You can use a generic function instead to extend the behaviour of
> map the way you want:
> 
> CL-USER 5 > (defmethod my-map (result-type operator (x sequence)(y sequence))
>               (map result-type operator x y))
> #<STANDARD-METHOD MY-MAP NIL (T T SEQUENCE SEQUENCE) 206F4864>
> 
> CL-USER 6 > (defmethod my-map (result-type operator (x number) (y sequence))
>               (map result-type (lambda (y-elt)(funcall operator x y-elt)) y))
> #<STANDARD-METHOD MY-MAP NIL (T T NUMBER SEQUENCE) 206EAF64>
> 
> CL-USER 7 > (my-map 'list #'* 5 '(1 2 3 4))
> (5 10 15 20)
> 
> CL-USER 8 > (my-map 'list #'* '(5 10 20 30) '(1 2 3 4))
> (5 20 60 120)
> 

Well, that would work for binary operators, but what if I want something 
like (my-map 'list #* list1 number2 list 3 number4 number5 list6 list7) 
or even more ?

Martin
From: Kenny Tilton
Subject: Re: About a macro
Date: 
Message-ID: <q66Xb.202180$4F2.26462267@twister.nyc.rr.com>
Martin Raspaud wrote:

> Espen Vestre a �crit :
> 
>> Martin Raspaud <··············@wanadoo.fr> writes:
>>
>>
>>> I'm quite new to lisp, but I started writing a bit of code... Things
>>> are getting on well (at least, it's working) but I didn't use any
>>> macro yet... I'm reading Paul Graham's "On Lisp" which I find great,
>>> but I'm still not very at ease with macros. 
>>
>>
>>
>> Hmm, are you sure you're ready for "On Lisp" yet? Most lisp programmers
>> (myself included) dive into macros a little to early.
> 
> 
> Yep maybe, but better soon than never ;-)

Well, I think the point was not never to use them, but not to dive in to 
macros just for the sake of using macros. But I like your 
damn-the-torpedos attitude, so...

Methinks one problem is that the macro will only see the source, and I 
wager you would like to use more than literals with your little hack. So 
something like:

   (let ((op1 3)(op2 #(1 2 3))) (good-luck '* op1 op2))

...well, needs more than luck, it needs run-time dispatch (in some form 
or other) based on the types of the objects bound to op1 and op2. A 
macro could expand into all the same dispatching source that would go 
into a function, but there is no point in that.

As for the GF's espen proposed only working where there are two 
operands, check out REDUCE. But then you have the problem of generating 
methods for each permutation:

   (my+ number sequence)
   (my+ sequence number)

..etc. This is where you could use a macro to take one definition and 
have it write the permutations.

kt
From: Martin Raspaud
Subject: Re: About a macro
Date: 
Message-ID: <c0iri3$8jk$1@news-reader1.wanadoo.fr>
Kenny Tilton a �crit :
> 
> 
> Martin Raspaud wrote:
> 
>> Espen Vestre a �crit :
>>
>>> Martin Raspaud <··············@wanadoo.fr> writes:
>>>
>>>
>>>> I'm quite new to lisp, but I started writing a bit of code... Things
>>>> are getting on well (at least, it's working) but I didn't use any
>>>> macro yet... I'm reading Paul Graham's "On Lisp" which I find great,
>>>> but I'm still not very at ease with macros. 
>>>
>>>
>>>
>>>
>>> Hmm, are you sure you're ready for "On Lisp" yet? Most lisp programmers
>>> (myself included) dive into macros a little to early.
>>
>>
>>
>> Yep maybe, but better soon than never ;-)
> 
> 
> Well, I think the point was not never to use them, but not to dive in to 
> macros just for the sake of using macros. But I like your 
> damn-the-torpedos attitude, so...
> 
> Methinks one problem is that the macro will only see the source, and I 
> wager you would like to use more than literals with your little hack. So 
> something like:
> 
>   (let ((op1 3)(op2 #(1 2 3))) (good-luck '* op1 op2))
> 
> ...well, needs more than luck, it needs run-time dispatch (in some form 
> or other) based on the types of the objects bound to op1 and op2. A 
> macro could expand into all the same dispatching source that would go 
> into a function, but there is no point in that.

I thought that the macro could recognize whether the argument was a 
sequence or not... If I understood things well, a macro is expanded at 
compile time, so in my program when I call (my-macro 'list (+ '(1 2 3) 
5)) why would the macro be unable to sort out the type of the arguments 
? '(1 2 3) is a list, even at compile-time, is it not ?

> As for the GF's espen proposed only working where there are two 
> operands, check out REDUCE. But then you have the problem of generating 
> methods for each permutation:
> 
>   (my+ number sequence)
>   (my+ sequence number)
> 
> ..etc. This is where you could use a macro to take one definition and 
> have it write the permutations.

Well, so I guess I understood wrong Paul Graham's sentence about macros 
being transformations... I'll just think about it, maybe I'll understand 
it some day (the day I'll be ready for macros ?)...

Martin
From: Paul Wallich
Subject: Re: About a macro
Date: 
Message-ID: <c0isnc$ia7$1@reader2.panix.com>
Martin Raspaud wrote:

> Kenny Tilton a �crit :
> 
>>
>>
>> Martin Raspaud wrote:
>>
>>> Espen Vestre a �crit :
>>>
>>>> Martin Raspaud <··············@wanadoo.fr> writes:
>>>>
>>>>
>>>>> I'm quite new to lisp, but I started writing a bit of code... Things
>>>>> are getting on well (at least, it's working) but I didn't use any
>>>>> macro yet... I'm reading Paul Graham's "On Lisp" which I find great,
>>>>> but I'm still not very at ease with macros. 
>>>>
>>>>
>>>>
>>>>
>>>>
>>>> Hmm, are you sure you're ready for "On Lisp" yet? Most lisp programmers
>>>> (myself included) dive into macros a little to early.
>>>
>>>
>>>
>>>
>>> Yep maybe, but better soon than never ;-)
>>
>>
>>
>> Well, I think the point was not never to use them, but not to dive in 
>> to macros just for the sake of using macros. But I like your 
>> damn-the-torpedos attitude, so...
>>
>> Methinks one problem is that the macro will only see the source, and I 
>> wager you would like to use more than literals with your little hack. 
>> So something like:
>>
>>   (let ((op1 3)(op2 #(1 2 3))) (good-luck '* op1 op2))
>>
>> ...well, needs more than luck, it needs run-time dispatch (in some 
>> form or other) based on the types of the objects bound to op1 and op2. 
>> A macro could expand into all the same dispatching source that would 
>> go into a function, but there is no point in that.
> 
> 
> I thought that the macro could recognize whether the argument was a 
> sequence or not... If I understood things well, a macro is expanded at 
> compile time, so in my program when I call (my-macro 'list (+ '(1 2 3) 
> 5)) why would the macro be unable to sort out the type of the arguments 
> ? '(1 2 3) is a list, even at compile-time, is it not ?

If that's all you're doing, fine. But it's more likely that you'll be 
calling (eventually if not now) (my-macro 'list (+ foo bar)) where foo 
and bar get passed in from an entirely different place. Or (my-macro 
'list (op-to-do foo bar)). And then you need a little more. If you're 
just operating on literals known at compile time, you barely need a macro.

paul
From: Kenny Tilton
Subject: Re: About a macro
Date: 
Message-ID: <5v6Xb.202379$4F2.26470400@twister.nyc.rr.com>
Martin Raspaud wrote:

> Kenny Tilton a �crit :
> 
>>
>>
>> Martin Raspaud wrote:
>>
>>> Espen Vestre a �crit :
>>>
>>>> Martin Raspaud <··············@wanadoo.fr> writes:
>>>>
>>>>
>>>>> I'm quite new to lisp, but I started writing a bit of code... Things
>>>>> are getting on well (at least, it's working) but I didn't use any
>>>>> macro yet... I'm reading Paul Graham's "On Lisp" which I find great,
>>>>> but I'm still not very at ease with macros. 
>>>>
>>>>
>>>>
>>>>
>>>>
>>>> Hmm, are you sure you're ready for "On Lisp" yet? Most lisp programmers
>>>> (myself included) dive into macros a little to early.
>>>
>>>
>>>
>>>
>>> Yep maybe, but better soon than never ;-)
>>
>>
>>
>> Well, I think the point was not never to use them, but not to dive in 
>> to macros just for the sake of using macros. But I like your 
>> damn-the-torpedos attitude, so...
>>
>> Methinks one problem is that the macro will only see the source, and I 
>> wager you would like to use more than literals with your little hack. 
>> So something like:
>>
>>   (let ((op1 3)(op2 #(1 2 3))) (good-luck '* op1 op2))
>>
>> ...well, needs more than luck, it needs run-time dispatch (in some 
>> form or other) based on the types of the objects bound to op1 and op2. 
>> A macro could expand into all the same dispatching source that would 
>> go into a function, but there is no point in that.
> 
> 
> I thought that the macro could recognize whether the argument was a 
> sequence or not... If I understood things well, a macro is expanded at 
> compile time, so in my program when I call (my-macro 'list (+ '(1 2 3) 
> 5)) why would the macro be unable to sort out the type of the arguments 
> ? '(1 2 3) is a list, even at compile-time, is it not ?

Yes, but you dashed through what I wrote too quickly. It is fine for you 
to tackle macros too soon since that only wastes your time. Now you are 
wasting mine. Bad, newbie! Bad! :)

Look at the example I gave and tell me what type you think the macro 
good-luck will see at compile-time.

Here's another problem of which I did not think:

(defmacro macriddle-1 (arg)
   (format t "~&yes I am a ~a, but why is my length ~a, not ~a?"
     (type-of arg) (length arg) (length (second arg))))

(macriddle-1 '(1 2 3))

=> yes I am a CONS, but why is my length 2, not 3?

kt


-- 
http://tilton-technology.com

Why Lisp? http://alu.cliki.net/RtL%20Highlight%20Film

Your Project Here! http://alu.cliki.net/Industry%20Application
From: Peter Seibel
Subject: Re: About a macro
Date: 
Message-ID: <m3smhfylio.fsf@javamonkey.com>
Martin Raspaud <··············@wanadoo.fr> writes:

> Well, so I guess I understood wrong Paul Graham's sentence about
> macros being transformations... I'll just think about it, maybe I'll
> understand it some day (the day I'll be ready for macros ?)...

You might be interested in taking a look at the chapter about macros
from my book in progress:

  <http://www.gigamonkeys.com/book/macros-defining-our-own.html>

They approach things a bit differently than Graham; maybe a new
perspective will help. If you read them and have any comments for me
I'd love to hear them. Other chapters ready for feedback are available
at:

  <http://www.gigamonkeys.com/book/>

-Peter

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

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Kenny Tilton
Subject: Re: About a macro
Date: 
Message-ID: <Xs7Xb.202385$4F2.26489148@twister.nyc.rr.com>
> Martin Raspaud <··············@wanadoo.fr> writes:
> 
> 
>>Well, so I guess I understood wrong Paul Graham's sentence about
>>macros being transformations...

I forgot to mention....

You dishonor macros twice, first by setting them on too high a pedestal, 
then in your disappointment setting them too low. (IP violation of 
Stendhal's chapter on "infatuation", in "On Love".)

Macros do /not/ see run-time types, they /do/ transform code.

kenny

-- 
http://tilton-technology.com

Why Lisp? http://alu.cliki.net/RtL%20Highlight%20Film

Your Project Here! http://alu.cliki.net/Industry%20Application
From: Espen Vestre
Subject: Re: About a macro
Date: 
Message-ID: <kwn07nxaju.fsf@merced.netfonds.no>
Martin Raspaud <··············@wanadoo.fr> writes:

> Well, that would work for binary operators, but what if I want
> something like (my-map 'list #* list1 number2 list 3 number4 number5
> list6 list7) or even more ?

Well, in that case at least I'm pretty sure you won't be able to do 
much fun with a macro, since the decision on what to do will have
to be done at run time (you don't know if the parameters are sequences
or numbers until run time). You could probably write my-map as a 
function that sorted numbers from sequences, used #'map on the
sequences and then treated the numbers.
-- 
  (espen)
From: Pascal Bourguignon
Subject: Re: About a macro
Date: 
Message-ID: <871xoyg85p.fsf@thalassa.informatimago.com>
Martin Raspaud <··············@wanadoo.fr> writes:

> Hi all,
> 
> I'm quite new to lisp, but I started writing a bit of code... Things
> are getting on well (at least, it's working) but I didn't use any
> macro yet... I'm reading Paul Graham's "On Lisp" which I find great,
> but I'm still not very at ease with macros. He writes that macros are
> made to transform expressions... So I thought "let's write a small
> macro for my needs" : I would like to extend classic arithmetic
> operations to sequences... for example
> (my-macro 'list (+ '(1 2 3) #(3 2 1))) would return (4 4 4), but also
> (my-macro 'vector (+ '(1 2 3) 5)) would return #(6 7 8) and
> (my-macro 'list (+ '(1 2 3) (* 5 '(1 2 3)))) would return (6 12 18)
> 
> so, take Paul Graham's method, I would write what I'll have to type :
> * (my-macro 'list (+ number1 sequence2 (* sequence3 number4)))
> 
> and that would expand to
> 
> (map 'list #'(lambda (x2 x3) (+ number1 x2 (* x3 number4))) sequence2
> sequence3)
> 
> but honestly I really don't know how to write the macro after
> that... The most mysterious part for me is how to transform the
> sequences in the original expression into variables for the lambda
> function...
> 
> Could anyone enlighten me ?


It  has not  been pointed  out  that you  can always  quote the  whole
expression to have it processed at run time by a function:

    (my-macro    'list  (+ '(1 2 3) (* 5 '(1 2 3))))
    (my-function 'list '(+  (1 2 3) (* 5  (1 2 3))))



Now,   what  would   be  important   in  your   case  is   to  specify
comprehensively  the  sematics  and  the  syntax you  want  for  these
expressions.

For example:

    expression   ::= sum | product | substraction | division .
    sum          ::= (+ term ... )
    product      ::= (* term ... )
    substraction ::= (- term term ... )
    division     ::= (/ term term ... )
    term         ::= expression | scalar_term | vector_term | list_term
    scalar_term  ::= number  ;; a lisp _number_.
    vector_term  ::= vector  ;; a lisp _vector_ of numbers.
    list_term    ::= list    ;; a lisp _list_ of numbers.
    
That  is, you  don't need  to  quote the  lists of  number inside  the
expression because  you can distinguish them from  expression by their
car being a number instead of being an operator.

Did I forgot variables?  You'd have to specify it!

Then you have to specify the sematics and semantic constraints of your
expressions:

    (+ seq1 ... seqn) --> (seq (+ (elt seq1 0) ... (elt seqn 0))
                               (+ (elt seq1 1) ... (elt seqn 1))
                               ...
                               (+ (elt seq1 p) ... (elt seqn p)))
    ;; seq is either vector or list depending on what result is expected.
    ;; seqi can be either a vector or a list.
    ;; what happens when (/= (length seqi) (length seqj)) ?

That may  seem obvious, but  writting out these  specifications you'll
see that  you'll discover questions that  need to be  answered, and at
the same  time you'll have defined an  abstract implementation: you'll
see better what you need to implement and therefore how to do it.


_Finally_, you'll  be able to make  a choice about whether  you need a
macro or a function to implement this.

Note that if you want to  be able to use variable in your expressions,
you could do either:

    (let ((my-vector #(1 2 3)))
      (my-function 'list `(+ (1 2 3) (* 5 ,my-vector))))

or:
    (let ((my-vector #(1 2 3)))
      (my-macro list (+ (1 2 3) (* 5 my-vector))))


(Is it worth a macro?)
Anyway you can always implement my-macro as a call to my-function:


    (defmacro my-macro (result-type expression)
        (let ((expr (back-un-quote expression)))
           `(my-fun ',result-type ,expr)))

With:

(defun back-un-quote (expr)
  (cond
   ((atom    expr) expr)
   ((consp   expr) `(list ,(if (symbolp (car expr))
                             `',(car expr)
                             (car expr))
                        ,@(mapcar (function back-un-quote) (cdr expr))))))

[49]> (back-un-quote '(+ (1 2 3) (* 5 my-vector)))
(LIST '+ (LIST 1 2 3) (LIST '* 5 MY-VECTOR))


-- 
__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: Martin Raspaud
Subject: Re: About a macro
Date: 
Message-ID: <c0q7vk$psb$1@news-reader5.wanadoo.fr>
Martin Raspaud wrote :
> Hi all,
> 
> [bla bla bla]
> 
> Martin
> 


Thanks all, I think I got the point (more or less).  Anyway, sorry for 
wasting your time ;-)

Martin
From: Joe Marshall
Subject: Re: About a macro
Date: 
Message-ID: <smhbw7qt.fsf@comcast.net>
Martin Raspaud <··············@wanadoo.fr> writes:

> Martin Raspaud wrote :
>> Hi all,
>> [bla bla bla]
>> Martin
>>
>
>
> Thanks all, I think I got the point (more or less).  Anyway, sorry for
> wasting your time ;-)

I think you were attempting something too ambitious for a simple macro.
(and I think that extending generic arithmetic to encompass sequences
is probably not something for a macro anyway).


-- 
~jrm