From: ············@gmail.com
Subject: Newbie Macro Question
Date: 
Message-ID: <1142654632.523060.95370@i39g2000cwa.googlegroups.com>
(Disclaimer: NEWBIE)
The book states:

"Lisp macros take are executed at compiler pre-processor time. The
resultant code gets executed at run-time."

Suppose I want a macro that makes a list of X number of sevens, i.e
when this is called

(give-me-a-list-of-X-sevens 3)

the macro should return this code:

(list 7 7 7)

I know it's a poor example, but anyways. The point is that the compiler
cannot know at preprocessor time the value of X and thus how many 7s
put in the list instruction. Can someone explain what happens here?

(also, if someone can show me how to write that macro using dotimes
please do)

From: Peter Seibel
Subject: Re: Newbie Macro Question
Date: 
Message-ID: <m24q1w1dg1.fsf@gigamonkeys.com>
············@gmail.com writes:

> (Disclaimer: NEWBIE)
> The book states:
>
> "Lisp macros take are executed at compiler pre-processor time. The
> resultant code gets executed at run-time."
>
> Suppose I want a macro that makes a list of X number of sevens, i.e
> when this is called
>
> (give-me-a-list-of-X-sevens 3)
>
> the macro should return this code:
>
> (list 7 7 7)
>
> I know it's a poor example, but anyways. The point is that the compiler
> cannot know at preprocessor time the value of X and thus how many 7s
> put in the list instruction. Can someone explain what happens here?

Sure it can, you passed it the literal object 3:

  (defmacro give-me-a-list-of-X-sevens (num)
    `(list ,@(loop repeat num collect 7)))

That is, at macro-expansion time (a better term than "compiler
pre-processor time", btw), the parameter NUM is bound to the object 3.
However, if the macro is written that way, you can't do is this:

  (let ((x 3))
    (give-me-a-list-of-X-sevens x))

because the macro GIVE-ME-A-LIST-OF-X-SEVENS will get the object X
(i.e. the symbol named "X") and will try and use it as an argument to
the REPEAT clause of the LOOP which will barf. If you understand the
difference between these two cases you will be well on your way to
grokking macros.

-Peter

P.S. if you wanted both uses of the macro to "work" you might write it
like this:

  (defmacro give-me-a-list-of-x-sevens (num)
    (typecase num
      (number `(list ,@(loop repeat num collect 7)))
      (t `(loop repeat ,num collect 7))))

in this version we generate (slightly) more efficient code in the case
where the value of num is known at macro-expansion time, and otherwise
generate code that does all the work at runtime.

-Peter

-- 
Peter Seibel           * ·····@gigamonkeys.com
Gigamonkeys Consulting * http://www.gigamonkeys.com/
Practical Common Lisp  * http://www.gigamonkeys.com/book/
From: Michael Parker
Subject: Re: Newbie Macro Question
Date: 
Message-ID: <180320060048574575%michaelparker@earthlink.net>
In article <·······················@i39g2000cwa.googlegroups.com>,
<············@gmail.com> wrote:

> (Disclaimer: NEWBIE)
> The book states:
> 
> "Lisp macros take are executed at compiler pre-processor time. The
> resultant code gets executed at run-time."
> 
> Suppose I want a macro that makes a list of X number of sevens, i.e
> when this is called
> 
> (give-me-a-list-of-X-sevens 3)
> 
> the macro should return this code:
> 
> (list 7 7 7)
> 
> I know it's a poor example, but anyways. The point is that the compiler
> cannot know at preprocessor time the value of X and thus how many 7s
> put in the list instruction. Can someone explain what happens here?

It can if you pass it a literal number as the parameter.  If you pass
it in something more complicated then it won't work, though in that
case the macro can opt to expand into a loop instead of expanding into
the (list ...). 

> 
> (also, if someone can show me how to write that macro using dotimes
> please do)
>

CL-USER 8 > (defmacro give-me-a-list-of-X-sevens (x)
                          `(list ,@(loop for i from 0 below x
                                    collect 7)))
GIVE-ME-A-LIST-OF-X-SEVENS

CL-USER 9 > (macroexpand '(give-me-a-list-of-x-sevens 3))
(LIST 7 7 7)
T

CL-USER 10 > (give-me-a-list-of-x-sevens 3)
(7 7 7)

CL-USER 11 > (macroexpand (give-me-a-list-of-x-sevens x))

Error: In >= of (0 X) arguments should be of type REAL.
  1 (continue) Return a value to use.
  2 Supply a new second argument.
  3 (abort) Return to level 0.
  4 Return to top loop level 0.

Type :b for backtrace, :c <option number> to proceed,  or :? for other
options

CL-USER 12 : 1 > :a

CL-USER 17 > (defmacro give-me-a-list-of-X-sevens (x)
               (if (integerp x)
                   `(list ,@(loop for i from 0 below x
                                  collect 7))
               
                 `(loop for i from 0 below ,x
                        collect 7)))
GIVE-ME-A-LIST-OF-X-SEVENS

CL-USER 18 > (pprint (macroexpand '(give-me-a-list-of-x-sevens x)))

(BLOCK NIL
  (MACROLET ((LOOP-FINISH () '(GO #:|end-loop-869|)))
    (LET ((I 0) (#:|to-872| X) (#:|by-873| 1))
      (LET ((#:|accumulator-870| (LIST NIL)))
        (DECLARE (TYPE LIST #:|accumulator-870|))
        (LET ((#:|aux-var-875| #:|accumulator-870|))
          (TAGBODY (PROGN (WHEN (OR (>= I #:|to-872|)) (GO
#:|end-loop-869|)))
           #:|begin-loop-868| (SETQ #:|aux-var-875| (LAST (RPLACD
#:|aux-var-875| (LIST 7))))
                   (PROGN
                     (LET ((#:|temp-874| (+ I #:|by-873|))) (SETQ I
#:|temp-874|))
                     (WHEN (OR (>= I #:|to-872|)) (GO
#:|end-loop-869|)))
                   (GO #:|begin-loop-868|)
           #:|end-loop-869| (RETURN-FROM NIL (CDR
#:|accumulator-870|))))))))