# LISP Gods, is this possible?

This topic is 4336 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I am trying to write my own version of the 'dotimes' macro, which will repeat a statement (or block of statements) x number of times. However, if you supply a constant, I want to it repeat the statement x times and have it expand to
(progn
(statement1)
(statement2)
(statement3)
....
(statementx))


Right now, I have it seperated into two seperate macros, one of which just inserts a do, and does a loop from 0 to x-1. The other actually repeats the statement x times and puts the expansion inside a progn block like shown above. The first one will work with any value. The second one will only work with numerical constants. This is the correct behaviour, however, I need two seperate macros, and I think that's ugly. Is there any way for me to tell if the given value is a compile-time (macro-expansion time) constant? I've tried different combinations of numberp, symbolp, and boundp, none of which seem to work. The problem is I can't call numberp / symbolp on a symbol that isn't bound yet (none of hte symbols are bound during macro-expansion time), and I can't call boundp on an integer or (quote integer). Any suggestions? The constant version
(defmacro mydotimes-helper (n continuation body)
(if (= n 0)
(progn ,@continuation)
(mydotimes-helper ,(1- n) ,(append continuation body) ,body)))

(defmacro mydotimes (n &rest body)
(mydotimes-helper ,n () ,body))


The non-constant version just calls the existing standard dotimes macro. (boundp 6) ERROR (boundp '6) ERROR (numberp f) ERROR (every symbol seems to be unbound during macro-expansion time) (numberp 'f) NIL

##### Share on other sites
I'm a bit sleepy atm but shouldn't the following work?
(defmacro footimes (arg &body body)  (if (symbolp arg)    (dotimes (,(gensym) ,arg)       ,@body)    (cons 'progn          (loop for i from 0 to arg collect                (car body)))))

Since the argument symbol is interned at readtime you should be able to use symbolp to check it.

##### Share on other sites
Ok, symbolp works =].

Quote:
 Original post by FlatlanderSince the argument symbol is interned at readtime ...

I didn't think the symbols were interned at readtime. I feel very sheepish.

  (defmacro footimes ((i arg) &body body)    (if (symbolp arg)      (dotimes (,i ,arg)         ,@body)      (cons 'progn (append                (loop for x from 0 to (- arg 1) collect                   (let ((,i ,x)) ,@body))                (list ())))))

The above code works perfectly. Now I'm just wondering how to get this to over-ride the default dotimes() macro. THe problem is, it relies on dotimes. I'm having trouble getting macrolet to let me rename the original dotimes to something like old-dotimes.

##### Share on other sites
Redefining contents(like DOTIMES) of COMMON-LISP package has undefined consequences. Instead you should make a new package (DEFPACKAGE) and define your own DOTIMES in there. Then you can refer to the original DOTIMES as CL:DOTIMES.
See
http://www.lisp.org/HyperSpec/Body/chap-11.html
http://gigamonkeys.com/book/programming-in-the-large-packages-and-symbols.html

If you are doing this as an optimization perhaps you should reconsider your approach. Where this kind of loop unrolling would have an effect a decent compiler should do it automatically for you. I would be curious to know if it really has an positive effect on performance on some implementation/situation.

##### Share on other sites
Shouldn't you use something besides symbolp since you could also include an expression (that would be evaluated after the macro)? In other words, it should be something like
if(not number) {insert dotimes} else {repeat statement [number] times}
Unfortunately, I my Lisp reference isn't available at the moment and it's been so long since I've used Lisp that I can't remeber the name of the predicate to test for an integer.

##### Share on other sites
Ok, (not (numberp arg)) works correnctly, it handles arbitrary expressions properly.

I'm not seriously trying to do this as an optimization, I'm well aware that the compiler does this kind of thing for you. I'm just testing out the possibilities of Common Lisp macros, I'm still deciding whether to use Common Lisp or something like Scheme/Dylan for some small projects, but so far I've found that Scheme/Dylan macros simply aren't capable of some of the things that Common Lisp macros are. For instance, the above macro has no equivalent in Scheme or Dylan.

As for overriding the original macro, it's certainly bad practice, but I'd like to know if it's possible, and how to overwrite an existing macro (say, if I ever wanted to add some kind of automatic logging functionality to certain macros).