From: alex
Subject: generating random list at compile-time
Date: 
Message-ID: <1171386164.701971.252920@q2g2000cwa.googlegroups.com>
hi,
i'm trying to write a macro that generates a list with random integer
numbers at compile-time.

(defmacro cmake-random-list (n &optional (seed 1000))
  "compile-time random list generation"
  (let ((res nil))
    `(progn
      ,(dotimes (i n)
		(push (random seed) res))
      ,res)))

(defun csort-test ()
  (sort (cmake-random-list 100) #'>))

when i compile the function i get the following error log:
; In: LAMBDA NIL

;   (CMAKE-RANDOM-LIST 100)
; --> PROGN
; ==>
;   (533 553 44 840 652 ...)
; Error: Illegal function call.
<-- ???
;
;   (SORT (CMAKE-RANDOM-LIST 100) #'>)
; Note: The first argument never returns a value.
;
;   #'>
; Note: Deleting unreachable code.
;
; Compiling LAMBDA NIL:
; Compiling Top-Level Form:

; Compilation unit finished.
;   1 error
;   2 notes

CSORT-TEST
T
T

it looks to me, as if it would basically work(the partitially
generated list is displayed in the output). but what is it with the
note "illegal function call"?

i'd be grateful for help!

kind regards, alex

From: Lars Rune Nøstdal
Subject: Re: generating random list at compile-time
Date: 
Message-ID: <pan.2007.02.13.17.11.00.961743@gmail.com>
On Tue, 13 Feb 2007 09:02:44 -0800, alex wrote:

> (defmacro cmake-random-list (n &optional (seed 1000))
>   "compile-time random list generation"
>   (let ((res nil))
>     `(progn
>       ,(dotimes (i n)
> 		(push (random seed) res))
>       ,res)))

Why not take a look at what's going on? You can see what it expands to by
doing:

cl-user> (macroexpand-1 '(cmake-random-list 5))
(progn nil (100 830 256 753 978))

Or you can (in Slime) press C-c <enter> while your cursor is at the
opening parenthesis of the, or any - macro call to (c-make-random-list 5).

As you can see it's returning something that does not make sense. You'll
want something like:


(defmacro cmake-random-list (n &optional (seed 1000))
  "compile-time random list generation"
  (let ((res nil))
    (dotimes (i n)
      (push (random seed) res))
    `,res))

(cmake-random-list 5) ==C-c<enter>==> (539 72 174 848 116)

..or..

(defmacro cmake-random-list (n &optional (seed 1000))
  "compile-time random list generation"
  (let ((res nil))
    (dotimes (i n)
      (push (random seed) res))
    `(list ,@res)))

(cmake-random-list 5) ==C-c<enter>==> (list 209 46 718 321 982)


Slime is great; isn't it? :) You can keep pressing C-c<enter> and expand
multiple levels into macro-macro-macro-calls.

-- 
Lars Rune Nøstdal
http://nostdal.org/
From: alex
Subject: Re: generating random list at compile-time
Date: 
Message-ID: <1171393085.484631.104090@m58g2000cwm.googlegroups.com>
On 13 Feb., 18:11, Lars Rune Nøstdal <···········@gmail.com> wrote:
> On Tue, 13 Feb 2007 09:02:44 -0800, alex wrote:
> > (defmacro cmake-random-list (n &optional (seed 1000))
> >   "compile-time random list generation"
> >   (let ((res nil))
> >     `(progn
> >       ,(dotimes (i n)
> >            (push (random seed) res))
> >       ,res)))
>
> Why not take a look at what's going on? You can see what it expands to by
> doing:
>
> cl-user> (macroexpand-1 '(cmake-random-list 5))
> (progn nil (100 830 256 753 978))
>
> Or you can (in Slime) press C-c <enter> while your cursor is at the
> opening parenthesis of the, or any - macro call to (c-make-random-list 5).
>
> As you can see it's returning something that does not make sense. You'll
> want something like:
>
> (defmacro cmake-random-list (n &optional (seed 1000))
>   "compile-time random list generation"
>   (let ((res nil))
>     (dotimes (i n)
>       (push (random seed) res))
>     `,res))
>
> (cmake-random-list 5) ==C-c<enter>==> (539 72 174 848 116)
hhm, this code also returns 2 things. macroexpand-1 says:

CL-USER> (macroexpand-1 '(cmake-random-list 3))
(899 56 690)
T

i still don't get why the macro can't be called normally without an
error( (cmake-random-list 3) ).
another question concerning your code: i want all the processing
happen at compile-time. so it's necessary to evaluate the dotimes-
statement at macroexpansion-time. but then i definetely need something
like ,(dotimes ...) don't I? otherwise it gets evaluated at runtime?!

thanks for your help.
From: Wolfram Fenske
Subject: Re: generating random list at compile-time
Date: 
Message-ID: <1171398498.619100.183850@p10g2000cwp.googlegroups.com>
"alex" <···············@gmail.com> writes:

> On 13 Feb., 18:11, Lars Rune Nstdal <···········@gmail.com> wrote:
>> On Tue, 13 Feb 2007 09:02:44 -0800, alex wrote:

[...]

>> As you can see it's returning something that does not make sense. You'll
>> want something like:
>>
>> (defmacro cmake-random-list (n &optional (seed 1000))
>>   "compile-time random list generation"
>>   (let ((res nil))
>>     (dotimes (i n)
>>       (push (random seed) res))
>>     `,res))
>>
>> (cmake-random-list 5) ==C-c<enter>==> (539 72 174 848 116)
> hhm, this code also returns 2 things. macroexpand-1 says:
>
> CL-USER> (macroexpand-1 '(cmake-random-list 3))
> (899 56 690)
> T
>
> i still don't get why the macro can't be called normally without an
> error( (cmake-random-list 3) ).

What's the error?  That 899 (or what ever is the first element of the
list) isn't a function?  Then you probably want to quote the list:

--8<---------------cut here---------------start------------->8---
(defmacro cmake-random-list (n &optional (seed 1000))
   "compile-time random list generation"
   (let ((res nil))
     (dotimes (i n)
       (push (random seed) res))
     `(quote ,res))) ; <-- quote res
--8<---------------cut here---------------end--------------->8---

(You can also write `',res instread of `(quote ,res) if you like that
better.)

> another question concerning your code: i want all the processing
> happen at compile-time. so it's necessary to evaluate the dotimes-
> statement at macroexpansion-time.

Lars' version of the macro does this.

> but then i definetely need something like ,(dotimes ...) don't I?

No.  You're confusing backquote syntax with macro-expansion.  They are
orthogonal.  Backquote syntax is just an efficient notation for
constructing lists.  Instead of

    (append (list 'foo) (list bar) baz)

it allows you to write

    `(foo ,bar ,@baz)

It just so happens that you create a lot of complicated list
structures in macros, and this is why backquote syntax is used in
almost every macro.

Now, about macro-expansion-time: every time a macro is "called", that
is, when the compiler sees a list in a value position whose CAR is the
name of a macro, the macro is called and the list is replaced with the
value returned by the macro.  For example, if you have this source
code:

--8<---------------cut here---------------start------------->8---
  (let ((foo (cmake-random-list 3)))
    (do-something foo))
--8<---------------cut here---------------end--------------->8---

it gets macro-expanded to this:

--8<---------------cut here---------------start------------->8---
  (let ((foo (899 56 690)))
    (do-something foo))
--8<---------------cut here---------------end--------------->8---

The DOTIMES loop and all that is evaluated at macro-expansion-time.
Only the s-expression that is returned by the macro is evaluated at
runtime.

If you don't know Peter Seibel's excellent book "Practical Common
Lisp", yet, here's the link to the second chapter about macros:

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

There's a section called "Macro Expansion Time vs. Runtime" that
explains this much better than I can.

--
Wolfram Fenske

A: Yes.
>Q: Are you sure?
>>A: Because it reverses the logical flow of conversation.
>>>Q: Why is top posting frowned upon?
From: Alex Mizrahi
Subject: Re: generating random list at compile-time
Date: 
Message-ID: <45d2f317$0$90264$14726298@news.sunsite.dk>
(message (Hello 'Wolfram)
(you :wrote  :on '(13 Feb 2007 12:28:18 -0800))
(

 WF> What's the error?  That 899 (or what ever is the first element of the
 WF> list) isn't a function?  Then you probably want to quote the list:

 WF> --8<---------------cut here---------------start------------->8---
 WF> (defmacro cmake-random-list (n &optional (seed 1000))
 WF>    "compile-time random list generation"
 WF>    (let ((res nil))
 WF>      (dotimes (i n)
 WF>        (push (random seed) res))
 WF>      `(quote ,res))) ; <-- quote res
 WF> --8<---------------cut here---------------end--------------->8---

 WF> (You can also write `',res instread of `(quote ,res) if you like that
 WF> better.)

is it possible to get a list from original macro (that doesn't insert quote) 
without explicit macroexpand call?

)
(With-best-regards '(Alex Mizrahi) :aka 'killer_storm)
"?? ???? ??????? ?????") 
From: Wolfram Fenske
Subject: Re: generating random list at compile-time
Date: 
Message-ID: <1171454411.961481.158790@q2g2000cwa.googlegroups.com>
"Alex Mizrahi" <········@users.sourceforge.net> writes:

> (message (Hello 'Wolfram)
> (you :wrote  :on '(13 Feb 2007 12:28:18 -0800))
> (
>
>  WF> What's the error?  That 899 (or what ever is the first element of the
>  WF> list) isn't a function?  Then you probably want to quote the list:
>
>  WF> --8<---------------cut here---------------start------------->8---
>  WF> (defmacro cmake-random-list (n &optional (seed 1000))
>  WF>    "compile-time random list generation"
>  WF>    (let ((res nil))
>  WF>      (dotimes (i n)
>  WF>        (push (random seed) res))
>  WF>      `(quote ,res))) ; <-- quote res
>  WF> --8<---------------cut here---------------end--------------->8---
>
>  WF> (You can also write `',res instread of `(quote ,res) if you like that
>  WF> better.)
>
> is it possible to get a list from original macro (that doesn't
> insert quote) without explicit macroexpand call?

I don't understand what you mean.  The original macro does return a
list, it's just that you'll get a runtime error if that code is ever
evaluated.  But you already knew that.  Is this a trick question? :-)

--
Wolfram Fenske

A: Yes.
>Q: Are you sure?
>>A: Because it reverses the logical flow of conversation.
>>>Q: Why is top posting frowned upon?
From: Pascal Bourguignon
Subject: Re: generating random list at compile-time
Date: 
Message-ID: <874ppokh93.fsf@thalassa.informatimago.com>
"Wolfram Fenske" <·····@gmx.net> writes:

> "Alex Mizrahi" <········@users.sourceforge.net> writes:
>
>> (message (Hello 'Wolfram)
>> (you :wrote  :on '(13 Feb 2007 12:28:18 -0800))
>> (
>>
>>  WF> What's the error?  That 899 (or what ever is the first element of the
>>  WF> list) isn't a function?  Then you probably want to quote the list:
>>
>>  WF> --8<---------------cut here---------------start------------->8---
>>  WF> (defmacro cmake-random-list (n &optional (seed 1000))
>>  WF>    "compile-time random list generation"
>>  WF>    (let ((res nil))
>>  WF>      (dotimes (i n)
>>  WF>        (push (random seed) res))
>>  WF>      `(quote ,res))) ; <-- quote res
>>  WF> --8<---------------cut here---------------end--------------->8---
>>
>>  WF> (You can also write `',res instread of `(quote ,res) if you like that
>>  WF> better.)
>>
>> is it possible to get a list from original macro (that doesn't
>> insert quote) without explicit macroexpand call?
>
> I don't understand what you mean.  The original macro does return a
> list, it's just that you'll get a runtime error if that code is ever
> evaluated.  But you already knew that.  Is this a trick question? :-)

Well that's the problem: a macro should return a FORM, not just a
list.  If you return just a list from a macro, you can still exploit
it, using macroexpand-1, but it is obviously a case when you shouldn't
use a macro but a function.

(defun f () '(1 2 3))   (f)
===
(defmacro m () '(1 2 3)) (macroexpand-1 '(m))


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
Wanna go outside.
Oh, no! Help! I got outside!
Let me back inside!
From: Pascal Bourguignon
Subject: Re: generating random list at compile-time
Date: 
Message-ID: <87d54cki7h.fsf@thalassa.informatimago.com>
"Alex Mizrahi" <········@users.sourceforge.net> writes:

> (message (Hello 'Wolfram)
> (you :wrote  :on '(13 Feb 2007 12:28:18 -0800))
> (
>
>  WF> What's the error?  That 899 (or what ever is the first element of the
>  WF> list) isn't a function?  Then you probably want to quote the list:
>
>  WF> --8<---------------cut here---------------start------------->8---
>  WF> (defmacro cmake-random-list (n &optional (seed 1000))
>  WF>    "compile-time random list generation"
>  WF>    (let ((res nil))
>  WF>      (dotimes (i n)
>  WF>        (push (random seed) res))
>  WF>      `(quote ,res))) ; <-- quote res
>  WF> --8<---------------cut here---------------end--------------->8---
>
>  WF> (You can also write `',res instread of `(quote ,res) if you like that
>  WF> better.)
>
> is it possible to get a list from original macro (that doesn't insert quote) 
> without explicit macroexpand call?

The question is why do you need it for?

For one thing, macroexpansion doesn't necessarily occur at compilation time(*).
But perhaps compilation time is not mandatory.

Then what about read time?  It could work as well...

  #.(loop  :repeat n :with max = 1000 :collect (random max))


To ensure compilation time, I'd write:

(eval-when (:compile-toplevel :load-toplevel :execute)
  (deFUN make-random-list (n &optional (max 1000))
    (loop  :repeat n :collect (random max))))

(eval-when (:compile-toplevel)
  (defvar *random-list* (make-random-list 10))
  (print `(while compiling , *random-list*)))

(eval-when (:execute)
  (unless (boundp '*random-list*)
    (format t "~&Loading file ~A without compilation!~%" *load-pathname*)
    (defvar *random-list* (make-random-list 10)))
  (print `(while loading , *random-list*)))





(*) For example, in the following case, (m 3) is expanded as many
    times it's executed: macroexpansion time is done at run-time by clisp:

C/USER5[47]> (load"/tmp/m.lisp")
;; Loading file /tmp/m.lisp ...
Macroexpansion of (m 1)
Execution of (m 1)
Macroexpansion of (m 2)
Macroexpansion of (m 3)
Execution of (m 3)
Macroexpansion of (m 3)
Execution of (m 3)
Macroexpansion of (m 3)
Execution of (m 3)
Macroexpansion of (m 4)
Execution of (m 2)
Execution of (m 4)
Execution of (m 4)
Execution of (m 4)
;; Loaded file /tmp/m.lisp
T
C/USER5[48]> (cat "/tmp/m.lisp")
(defmacro m (a)
  (format t "~&Macroexpansion of (m ~S)~%" a)
  `(format t "~&Execution of (m ~S)" ',a))

(m 1)
(defun f ()
  (m 2))

(loop :repeat 3 :do (m 3))

(defun g ()
  (loop :repeat 3 :do (m 4)))

(defun main ()
  (f)
  (g))

(main)

C/USER5[49]> 

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
Kitty like plastic.
Confuses for litter box.
Don't leave tarp around.
From: Alex Mizrahi
Subject: Re: generating random list at compile-time
Date: 
Message-ID: <45d45ee0$0$90276$14726298@news.sunsite.dk>
(message (Hello 'Pascal)
(you :wrote  :on '(Wed, 14 Feb 2007 14:00:02 +0100))
(

 ??>> is it possible to get a list from original macro (that doesn't insert
 ??>> quote) without explicit macroexpand call?

 PB> The question is why do you need it for?

just to check i'm not missing something important :).
i didn't find a way to get a result of macro as a value except doing 
macroexpand..
well, there's certainly a reason for this, but i thought maybe some clever 
backquote or whatever could do a trick..

 PB> (*) For example, in the following case, (m 3) is expanded as many
 PB>     times it's executed: macroexpansion time is done at run-time by 
clisp:

i suspected that :). once i've made a macro like

(defmacro thingie (&body)
    (let ((s (gensym))
      (setf (get s :counter) 0)
   `(progn
        (format t "called ~a times~%" (incf (get ,s :counter)))
        ,@body)))

(actually it was much more complex, only structure with gensym was such)

and i was surprised that it didn't work in clisp -- it did macroexpansion on 
each new invokation :-/

i didn't thought it depends on whether it is in top-level or in function..

)
(With-best-regards '(Alex Mizrahi) :aka 'killer_storm)
"?? ???? ??????? ?????") 
From: Pascal Bourguignon
Subject: Re: generating random list at compile-time
Date: 
Message-ID: <87abzfijx1.fsf@thalassa.informatimago.com>
"Alex Mizrahi" <········@users.sourceforge.net> writes:

> (message (Hello 'Pascal)
> (you :wrote  :on '(Wed, 14 Feb 2007 14:00:02 +0100))
> (
>
>  ??>> is it possible to get a list from original macro (that doesn't insert
>  ??>> quote) without explicit macroexpand call?
>
>  PB> The question is why do you need it for?
>
> just to check i'm not missing something important :).
> i didn't find a way to get a result of macro as a value except doing 
> macroexpand..

The point is that if you need the result of a macro AS a value, it
means you should write a function instead of a macro.

On the other hand, if you need the macro to return CODE that evaluates
to a value (any lisp code evaluates to some value), then a macro is of
course ok, but you should make it return CODE.  For example, a QUOTE form.

> well, there's certainly a reason for this, but i thought maybe some clever 
> backquote or whatever could do a trick..



-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

In a World without Walls and Fences, 
who needs Windows and Gates?
From: Tin Gherdanarra
Subject: Re: generating random list at compile-time
Date: 
Message-ID: <53el5qF1saffcU1@mid.individual.net>
> 
> i still don't get why the macro can't be called normally without an
> error( (cmake-random-list 3) ).
> another question concerning your code: i want all the processing
> happen at compile-time. so it's necessary to evaluate the dotimes-
> statement at macroexpansion-time. but then i definetely need something
> like ,(dotimes ...) don't I? otherwise it gets evaluated at runtime?!
> 
> thanks for your help.

Your macro returns an unquoted list:

	(1 9 3 6)
instead of
	'(1 9 3 6)

The PROG in your code is redundant because the PROG
is used to brace multiple expressions returned by
a single macro. You have only a single expression, that
is, your list. No PROG required. What's more, your
macro is unusual in that it does not return any code,
just data. This, too, obsoletes PROG.

As for the "1 is not a function", that's because
your Lisp Computer thinks that (1 9 3 6) is code,
but you want this to be data.
Return '(1 9 3 6). Here is a slight modification of
your macro

(defmacro cmake-random-list (n &optional (seed 1000))
   "compile-time random list generation"
   (let ((res nil))
     (dotimes (i n)
       (push (random seed) res))
     (list 'quote res)))



-- 
Lisp kann nicht kratzen, denn Lisp ist fluessig
From: Alex Mizrahi
Subject: Re: generating random list at compile-time
Date: 
Message-ID: <45d21802$0$49204$14726298@news.sunsite.dk>
(message (Hello 'alex)
(you :wrote  :on '(13 Feb 2007 10:58:05 -0800))
(

 a> (defmacro cmake-random-list (n &optional (seed 1000))
 a>   "compile-time random list generation"

this should be NOT called seed. seed is completely different thing..

 a> hhm, this code also returns 2 things. macroexpand-1 says:

 a> CL-USER> (macroexpand-1 '(cmake-random-list 3))
 a> (899 56 690)
 a> T

 a> i still don't get why the macro can't be called normally without an
 a> error( (cmake-random-list 3) ).

try it at your repl:

CL-USER> (899 56 690)

you'll have an error. because 899 is not a function!
you need QUOTE to stop evaluation (so it will not try to evaluation function 
899).

CL-USER> (quote (899 56 690))
(899 56 690)

or it can be written in short form '(899 56 690). you can check second 
version of Lars' code -- it adds list, you can call it normally.

 a> another question concerning your code: i want all the processing
 a> happen at compile-time. so it's necessary to evaluate the dotimes-
 a> statement at macroexpansion-time. but then i definetely need something
 a> like ,(dotimes ...) don't I? otherwise it gets evaluated at runtime?!

it's not `, make it to be evaluated at compile time. defmacro does this. so 
you can do this without any `:

(defmacro mklist (n &optional (limit 100))
  (loop repeat n collect (random limit))

if you want it to return list as value:

(defmacro mklist (n &optional (limit 100))
  (cons 'quote (cons  (loop repeat n collect (random limit)) nil)))

CL-USER> (macroexpand-1 '(mklist 5))
(QUOTE (66 68 20 32 95))
T
CL-USER> (mklist 5)
(70 65 21 79 88)

` is just a shorthand for a templates of code. you see cons stuff above is a 
bit clumsy, i can write it like

(defmacro mklist (n &optional (limit 100))
 `(quote ,(loop repeat n collect (random limit))))

it's exactly same as

(defmacro mklist (n &optional (limit 100))
    (let ((randomlist (loop repeat n collect (random limit))))
    `(quote ,randomlist)))

)
(With-best-regards '(Alex Mizrahi) :aka 'killer_storm)
"?? ???? ??????? ?????") 
From: alex
Subject: Re: generating random list at compile-time
Date: 
Message-ID: <1171403601.034638.278080@v45g2000cwv.googlegroups.com>
thank you for all the detailed explanations! helped me alot (for macro-
understanding in general) :)
From: Lars Rune Nøstdal
Subject: Re: generating random list at compile-time
Date: 
Message-ID: <pan.2007.02.13.17.14.03.145879@gmail.com>
On Tue, 13 Feb 2007 18:11:02 +0100, Lars Rune Nøstdal wrote:

> Or you can (in Slime) press C-c <enter> while your cursor is at the
> opening parenthesis of the, or any - macro call to (c-make-random-list 5).

I meant something like "..of the macro call to (c-make-random-list 5) or
any macro-call." here.

-- 
Lars Rune Nøstdal
http://nostdal.org/
From: Lars Rune Nøstdal
Subject: Re: generating random list at compile-time
Date: 
Message-ID: <pan.2007.02.13.17.20.36.543388@gmail.com>
On Tue, 13 Feb 2007 18:11:02 +0100, Lars Rune Nøstdal wrote:

> Slime is great; isn't it? :) You can keep pressing C-c<enter> and expand
> multiple levels into macro-macro-macro-calls.

Oh, and as always -- close down the temp-buffers showing the expansions by
pressing `q'. Check out the Slime manual:
http://common-lisp.net/project/slime/doc/html/

-- 
Lars Rune Nøstdal
http://nostdal.org/
From: Lars Rune Nøstdal
Subject: Re: generating random list at compile-time
Date: 
Message-ID: <pan.2007.02.13.21.32.31.838195@gmail.com>
On Tue, 13 Feb 2007 18:11:02 +0100, Lars Rune Nøstdal wrote:

> (defmacro cmake-random-list (n &optional (seed 1000))
>   "compile-time random list generation"
>   (let ((res nil))
>     (dotimes (i n)
>       (push (random seed) res))
>     `,res))
> 
> (cmake-random-list 5) ==C-c<enter>==> (539 72 174 848 116)

ups, that should have been:

(defmacro cmake-random-list (n &optional (seed 1000))
  "compile-time random list generation"
  (let ((res nil))
    (dotimes (i n)
      (push (random seed) res))
    `',res))

(cmake-random-list 5) ==C-c<enter>==> '(539 72 174 848 116)


-- 
Lars Rune Nøstdal
http://nostdal.org/