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

Am I understanding how macros work correctly?

108 views
Skip to first unread message

Yves S. Garret

unread,
Sep 5, 2012, 3:52:00 PM9/5/12
to
So I'm going through gigamonkeys, this chapter:
http://gigamonkeys.com/book/macros-defining-your-own.html

I get to the following snippet.

(do-primes (p 0 (random 100))
(format t "~d " p))

|
|
v

CL-USER> (macroexpand-1 '(do-primes (p 0 (random 100)) (format t "~d " p)))
(DO ((P (NEXT-PRIME 0) (NEXT-PRIME (1+ P))))
((> P (RANDOM 100)))
(FORMAT T "~d " P))
T



If I understand this correctly, the reason why random is run every time the do loop is run is because (random 100) is passed into the macro unevaluated and then put in place where the upper limit of the do-primes macro is supposed to do, yes? So, when the macro is run, the only time that the loop ends is when it gets to a point where a random number is generated is less than the iterated number and the loop exits, yes?

Also, how often would you say you use macros when writing Lisp code professionally or just in general?

Alberto Riva

unread,
Sep 5, 2012, 4:46:08 PM9/5/12
to
On 09/05/2012 03:52 PM, Yves S. Garret wrote:
> So I'm going through gigamonkeys, this chapter:
> http://gigamonkeys.com/book/macros-defining-your-own.html
>
> I get to the following snippet.
>
> (do-primes (p 0 (random 100))
> (format t "~d " p))
>
> |
> |
> v
>
> CL-USER> (macroexpand-1 '(do-primes (p 0 (random 100)) (format t "~d " p)))
> (DO ((P (NEXT-PRIME 0) (NEXT-PRIME (1+ P))))
> ((> P (RANDOM 100)))
> (FORMAT T "~d " P))
> T
>
>
>
> If I understand this correctly, the reason why random is run every
> time the do loop is run is because (random 100) is passed into the
> macro unevaluated and then put in place where the upper limit of the
> do-primes macro is supposed to do, yes?

Yes.

> So, when the macro is run,
> the only time that the loop ends is when it gets to a point where a
> random number is generated is less than the iterated number and the
> loop exits, yes?

Yes.

> Also, how often would you say you use macros when writing Lisp code
> professionally or just in general?

Almost every day.

Alberto


Frode V. Fjeld

unread,
Sep 5, 2012, 4:59:20 PM9/5/12
to
"Yves S. Garret" <yoursurr...@gmail.com> writes:

> If I understand this correctly, the reason why random is run every
> time the do loop is run is because (random 100) is passed into the
> macro unevaluated and then put in place where the upper limit of the
> do-primes macro is supposed to do, yes?

I wouldn't put it likt that. It's not that it's unevaluated, it's /how/
it's evaluated. A typical expansion for the macro you mentioned would
look something like this:

(let ((<random-var> (raondom 100)))
(do ....))

In fact, I'd say it's a general pattern for macros that a macro form
such as (my-macro arg1 arg2 arg3) should expand to something like

(let ((<arg1-var> arg1)
(<arg2-var> arg2)
(<arg3-var> arg3))
...)

for every arg that's supposed to be evaluated normally (i.e. evaluated
exactly once, in left-to-right order).


> So, when the macro is run, the only time that the loop ends is when
> it gets to a point where a random number is generated is less than the
> iterated number and the loop exits, yes?

Right.

> Also, how often would you say you use macros when writing Lisp code
> professionally or just in general?

That's impossible to answer, akin to "how often do you use arithmetics
in your code". It's a tool, extremely useful at times, and sometimes not
so much.

--
Frode V. Fjeld

Kaz Kylheku

unread,
Sep 5, 2012, 6:26:27 PM9/5/12
to
On 2012-09-05, Yves S. Garret <yoursurr...@gmail.com> wrote:
> So I'm going through gigamonkeys, this chapter:
> http://gigamonkeys.com/book/macros-defining-your-own.html
>
> I get to the following snippet.
>
> (do-primes (p 0 (random 100))
> (format t "~d " p))
>
> |
> |
> v
>
> CL-USER> (macroexpand-1 '(do-primes (p 0 (random 100)) (format t "~d " p)))
> (DO ((P (NEXT-PRIME 0) (NEXT-PRIME (1+ P))))
> ((> P (RANDOM 100)))
> (FORMAT T "~d " P))
> T
>
>
>
> If I understand this correctly, the reason why random is run every time the
> do loop is run is because (random 100) is passed into the macro unevaluated
> and then put in place where the upper limit of the do-primes macro is
> supposed to do, yes?

random is called on every iteration simply because the macro wrote the code
that way. Once you see the expanded code, you can just think about the expanded
code (if you want). The code is what it is, and evaluates the expression
(random 100) on each iteration.

The macro took the piece of source code denoted by (random 100) and stuck it
into the DO loop form in that way.

The form could be placed into the DO loop in a different way such that it
is just evaluated once. If, in a DO variable binding you only have a
single expression, rather than two, then instead of stepping, you get
a one time initialization.

(do ((r100 (random 100))
(p (next-prime 0) (next-prime (1+ p))))
((> p r100))
...)

So it is all about how you stick that piece of code into the target
code template: what evaluation rules that piece of code is subjected to.

Problem is now that the body of do-primes has visibility to a variable
called r100 which does not appear anywhere in the do-primes syntax.
If the user happens to be using a variable called r100, there is a clash.
To do this right, we would have the macro invent a new uninterned symbol by
calling gensym, and insert that symbol instead of r100.

> So, when the macro is run, the only time that the loop
> ends is when it gets to a point where a random number is generated is less
> than the iterated number and the loop exits, yes?

Of course, this is indistinguishable from getting a single random number.
You're just wasting machine cycles on getting unnecessary random numbers.

The probability that, on any given iteration, the loop will end, is exactly the
same whether you pick a new number each time, or stick with one initially
chosen random number.

> Also, how often would you say you use macros when writing Lisp code professionally or just in general?

It's nearly impossible to write Lisp code without *using* a macro, such as
DEFUN. You benefit from using other people's macros, including the ones in the
language, even if you do not write any of your own. Outside of the language
proper, you will find that many libraries will have useful macros.

How often do you write your own macros? Quite a lot, possibly.
Any time you have some repeating tedious coding pattern with some variation,
there may be a macro hiding in there wanting to unify and condense it all.

Any nontrivial Common Lisp program is usually going to have some fraction of
its code represented by macros, unless it's written by someone who wants to
avoid macros at all costs. A good way to answer this question might be to
sample some open source Lisp projects, looking for "macro": calls to defmacro,
symbol-macrolet, macrolet, define-symbol-macro and define-compiler-macro.


--
If you ever need any coding done, I'm your goto man!

Pascal J. Bourguignon

unread,
Sep 5, 2012, 9:55:13 PM9/5/12
to
"Yves S. Garret" <yoursurr...@gmail.com> writes:


> Also, how often would you say you use macros when writing Lisp code
> professionally or just in general?

Do not ask US such a question!
Ask the sources!

find ~/quicklisp -name \*.lisp -exec cat {} \; | grep --count -i defmacro
find ~/quicklisp -name \*.lisp -exec cat {} \; | grep --count -i defun

--
__Pascal Bourguignon__ http://www.informatimago.com/
A bad day in () is better than a good day in {}.

Norbert_Paul

unread,
Sep 6, 2012, 3:15:33 AM9/6/12
to
Frode V. Fjeld wrote:
> "Yves S. Garret"<yoursurr...@gmail.com> writes:

> I wouldn't put it likt that. It's not that it's unevaluated, it's /how/
> it's evaluated. A typical expansion for the macro you mentioned would
> look something like this:
>
> (let ((<random-var> (raondom 100)))
> (do ....))

This is exactly what the discussion in
http://gigamonkeys.com/book/macros-defining-your-own.html
is about. You should have followed Yves' link first.


Yves S. Garret

unread,
Sep 6, 2012, 9:32:53 AM9/6/12
to
Why not?

Pascal J. Bourguignon

unread,
Sep 6, 2012, 10:49:46 AM9/6/12
to
"Yves S. Garret" <yoursurr...@gmail.com> writes:

> On Wednesday, September 5, 2012 9:55:15 PM UTC-4, informatimago wrote:
>> "Yves S. Garret" <yoursurr...@gmail.com> writes:
>>
>>
>>
>>
>>
>> > Also, how often would you say you use macros when writing Lisp code
>>
>> > professionally or just in general?
>>
>>
>>
>> Do not ask US such a question!
>>
>> Ask the sources!
>>
>>
>>
>> find ~/quicklisp -name \*.lisp -exec cat {} \; | grep --count -i defmacro
>>
>> find ~/quicklisp -name \*.lisp -exec cat {} \; | grep --count -i defun
>>
>>
>>
>> --
>>
>> __Pascal Bourguignon__ http://www.informatimago.com/
>>
>> A bad day in () is better than a good day in {}.
>
> Why not?

So, what's the ratio of defmacros over defuns?

Yves S. Garret

unread,
Sep 6, 2012, 11:30:42 AM9/6/12
to
On Thursday, September 6, 2012 10:49:48 AM UTC-4, informatimago wrote:
> "Yves S. Garret" <yoursurr...@gmail.com> writes:
>
>
>
> > On Wednesday, September 5, 2012 9:55:15 PM UTC-4, informatimago wrote:
>
> >> "Yves S. Garret" <yoursurr...@gmail.com> writes:
>
> >>
>
> >>
>
> >>
>
> >>
>
> >>
>
> >> > Also, how often would you say you use macros when writing Lisp code
>
> >>
>
> >> > professionally or just in general?
>
> >>
>
> >>
>
> >>
>
> >> Do not ask US such a question!
>
> >>
>
> >> Ask the sources!
>
> >>
>
> >>
>
> >>
>
> >> find ~/quicklisp -name \*.lisp -exec cat {} \; | grep --count -i defmacro
>
> >>
>
> >> find ~/quicklisp -name \*.lisp -exec cat {} \; | grep --count -i defun
>
> >>
>
> >>
>
> >>
>
> >> --
>
> >>
>
> >> __Pascal Bourguignon__ http://www.informatimago.com/
>
> >>
>
> >> A bad day in () is better than a good day in {}.
>
> >
>
> > Why not?
>
>
>
> So, what's the ratio of defmacros over defuns?
>
>
>
> --
>
> __Pascal Bourguignon__ http://www.informatimago.com/
>
> A bad day in () is better than a good day in {}.

I'd imagine defuns would dwarf defmacros.

Looking back on my previous question, I realized that I meant to say "write" as opposed to "use". The reason why is because I don't have the mastery of developing macros as I'd like to have and would like to know if it will stop me in my tracks when it comes to learning how to write code in lisp.

Pascal J. Bourguignon

unread,
Sep 6, 2012, 6:52:22 PM9/6/12
to
Well, you'll be able to go at least as far as in the other programming
languages, with lisp without defining your own macros.

Alberto Riva

unread,
Sep 7, 2012, 11:19:01 AM9/7/12
to
On 09/06/2012 11:30 AM, Yves S. Garret wrote:
> Looking back on my previous question, I realized that I meant to say
> "write" as opposed to "use". The reason why is because I don't have
> the mastery of developing macros as I'd like to have and would like
> to know if it will stop me in my tracks when it comes to learning how
> to write code in lisp.

The thing is... you don't really *need* to write macros in order to
write code in Lisp. Anything that a macro does you can do yourself
manually (by rewriting your code the same way a macro would). Then you
will start realizing that you're doing a lot of repetitive work that
could be done for you by a function, and you will get the point of macros.

From there to actually writing macros, it's a small step... you can
start by asking yourself how you would rewrite simple ones like PUSH or
INCF. Then move on to something like WITH-OPEN-FILE, and you'll get it :)

Alberto

Yves S. Garret

unread,
Sep 7, 2012, 11:22:15 AM9/7/12
to
Thank you Alberto. I kinda figured that I'd follow that path towards my Lisp mastery. I'm not sweating over Macros. Something tells me that I'll go back and start re-reading what I have studied before because I didn't really comprehend all of it.
0 new messages