Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

About a macro

6 views
Skip to first unread message

Martin Raspaud

unread,
Feb 13, 2004, 9:17:29 AM2/13/04
to
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

Espen Vestre

unread,
Feb 13, 2004, 10:03:43 AM2/13/04
to
Martin Raspaud <martin....@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)

Martin Raspaud

unread,
Feb 13, 2004, 10:16:24 AM2/13/04
to
Espen Vestre a écrit :

> Martin Raspaud <martin....@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, 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

Espen Vestre

unread,
Feb 13, 2004, 10:29:25 AM2/13/04
to
Martin Raspaud <martin....@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)

Kenny Tilton

unread,
Feb 13, 2004, 10:32:38 AM2/13/04
to

Martin Raspaud wrote:

> Espen Vestre a écrit :
>
>> Martin Raspaud <martin....@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


Martin Raspaud

unread,
Feb 13, 2004, 10:47:14 AM2/13/04
to
Kenny Tilton a écrit :

>
>
> Martin Raspaud wrote:
>
>> Espen Vestre a écrit :
>>
>>> Martin Raspaud <martin....@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

Kenny Tilton

unread,
Feb 13, 2004, 10:58:57 AM2/13/04
to

Martin Raspaud wrote:

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

Peter Seibel

unread,
Feb 13, 2004, 11:47:20 AM2/13/04
to
Martin Raspaud <martin....@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 pe...@javamonkey.com

Lisp is the red pill. -- John Fraser, comp.lang.lisp

Kenny Tilton

unread,
Feb 13, 2004, 12:04:55 PM2/13/04
to

> Martin Raspaud <martin....@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

Pascal Bourguignon

unread,
Feb 13, 2004, 1:13:06 PM2/13/04
to
Martin Raspaud <martin....@wanadoo.fr> writes:


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/

Paul Wallich

unread,
Feb 13, 2004, 11:07:07 AM2/13/04
to
Martin Raspaud wrote:

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

Martin Raspaud

unread,
Feb 16, 2004, 6:02:11 AM2/16/04
to
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

Joe Marshall

unread,
Feb 16, 2004, 7:06:21 AM2/16/04
to
Martin Raspaud <martin....@wanadoo.fr> writes:

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

0 new messages