From: Franz Kafka
Subject: An intresting "Recursive" Macro.
Date: 
Message-ID: <okyxa.7610$eF1.448@news01.roc.ny.frontiernet.net>
;; A recursive macro that demonstrates Lisp's ability
;; to write Lisp code. :)

(defmacro worm (&optional (max-worms 50))
   (let ((fname (gensym)))
      `(progn
                  (defun ,fname ()
                      (format t "~&Worm Number: ~d" ,max-worms))
                  (if (= ,max-worms 0)
                                                  t
                                                  (worm (- ,max-worms 1)))
                  (,fname))))

;; Let's use this macro.
(worm 5) ;; equiv. to (worm 5)

#|
>Worm Number: 1
>Worm Number: 2
>Worm Number: 3
>Worm Number: 4
>Worm Number: 5
NIL
|#

;; Any one who wants to play with this code
;; be my guest.

;; Tested under Genera:
;;   1.) It compiles without bombing out.
;;   2.) It has not been confirmed to be ANSI. :)
;;   3.) Shows the power of Lisp Macros in a Toy-way ;)

From: Fred Gilham
Subject: Re: An intresting "Recursive" Macro.
Date: 
Message-ID: <u71xyxmc3k.fsf@snapdragon.csl.sri.com>
Franz Kafka wrote:
> ;; A recursive macro that demonstrates Lisp's ability
> ;; to write Lisp code. :)
> 
> (defmacro worm (&optional (max-worms 50))
>    (let ((fname (gensym)))
>       `(progn
>                   (defun ,fname ()
>                       (format t "~&Worm Number: ~d" ,max-worms))
>                   (if (= ,max-worms 0)
>                                                   t
>                                                   (worm (- ,max-worms 1)))
>                   (,fname))))

Goes into an infinite loop under CMU Lisp 18e.

I'd hate to think what all those worms are doing to my computer....

-- 
Fred Gilham                                        ······@csl.sri.com
...And then it got late, and I had to stop researching.  But it appears
that every slab of concrete in West Virginia is named after Bob Byrd.
                                                -- Ann Coulter 
From: Kent M Pitman
Subject: Re: An intresting "Recursive" Macro.
Date: 
Message-ID: <sfwllx5ur3k.fsf@shell01.TheWorld.com>
"Franz Kafka" <Symbolics _ XL1201 _ Sebek _ Budo _ Kafka @ hotmail . com> writes:

> ;; A recursive macro that demonstrates Lisp's ability
> ;; to write Lisp code. :)
> 
> (defmacro worm (&optional (max-worms 50))
>    (let ((fname (gensym)))
>       `(progn
>                   (defun ,fname ()
>                       (format t "~&Worm Number: ~d" ,max-worms))
>                   (if (= ,max-worms 0)
>                                                   t
>                                                   (worm (- ,max-worms 1)))
>                   (,fname))))
> 
> ;; Let's use this macro.
> (worm 5) ;; equiv. to (worm 5)
> 
> #|
> >Worm Number: 1
> >Worm Number: 2
> >Worm Number: 3
> >Worm Number: 4
> >Worm Number: 5
> NIL
> |#
> 
> ;; Any one who wants to play with this code
> ;; be my guest.
> 
> ;; Tested under Genera:
> ;;   1.) It compiles without bombing out.
> ;;   2.) It has not been confirmed to be ANSI. :)
> ;;   3.) Shows the power of Lisp Macros in a Toy-way ;)

This is not what it means to write recursive macros.

This is not conforming CL code.

The code you've written is not required to terminate when preprocessed
for compilation or evaluation.

You're doing  your testing (= max-worms 0) at runtime, but WORM is a macro
so is expanded at compile time.

In some implementations, the WORM macro will be expanded lazily when 
encountered in the interpreter.

In a conforming file compiler, it will not compile because minimal
compilation requires that full macroexpansion occur and also that no
execution occur, therefore runtime cannot be reached to do the end test.

If you want the test to happen at compile time (and I don't recommend
macros like this anyway, try:

(defmacro worm (&optional (max-worms 50))
  (check-type max-worms (integer 0) "a whole number")
  (let ((fname (gensym)))
    `(progn
       ;; It's pointless to gives this function a name and then call
       ;; it.  You could just as well just execute the body.
       (defun ,fname ()
         (format t "~&Worm Number: ~d" ,max-worms))
       ,(if (= max-worms 0) ;compile-time test
            `t
            `(worm ,(- max-worms 1))) ;compile-time computation
       (,fname))))

or just

(defmacro worm (&optional (max-worms 50))
  (check-type max-worms (integer 0) "a whole number")
  (let ((fname (gensym)))
    `(progn
       ;; It's pointless to gives this function a name and then call
       ;; it.  You could just as well just execute the body.
       ,(if (= max-worms 0) ;compile-time test
            `t
            `(worm ,(- max-worms 1))) ;compile-time computation
       (format t "~&Worm Number: ~d" ,max-worms))))

I've tried to stay inside the framework you set up.  However, generally
almost all the programs I've ever written that do this have been bad
styled programs that have led to trouble.
From: Franz Kafka
Subject: Re: An intresting "Recursive" Macro.
Date: 
Message-ID: <efAxa.7566$xm.4818@news02.roc.ny.frontiernet.net>
"Kent M Pitman" <······@world.std.com> wrote in message
····················@shell01.TheWorld.com...
> "Franz Kafka" <Symbolics _ XL1201 _ Sebek _ Budo _ Kafka @ hotmail . com>
writes:

>
> If you want the test to happen at compile time (and I don't recommend
> macros like this anyway, try:
>
> (defmacro worm (&optional (max-worms 50))
>   (check-type max-worms (integer 0) "a whole number")
>   (let ((fname (gensym)))
>     `(progn
>        ;; It's pointless to gives this function a name and then call
>        ;; it.  You could just as well just execute the body.
>        (defun ,fname ()
>          (format t "~&Worm Number: ~d" ,max-worms))
>        ,(if (= max-worms 0) ;compile-time test
>             `t
>             `(worm ,(- max-worms 1))) ;compile-time computation
>        (,fname))))
>
> or just
>
> (defmacro worm (&optional (max-worms 50))
>   (check-type max-worms (integer 0) "a whole number")
>   (let ((fname (gensym)))
>     `(progn
>        ;; It's pointless to gives this function a name and then call
>        ;; it.  You could just as well just execute the body.
>        ,(if (= max-worms 0) ;compile-time test
>             `t
>             `(worm ,(- max-worms 1))) ;compile-time computation
>        (format t "~&Worm Number: ~d" ,max-worms))))
>

Thanks for the advice.

BTW, where would I learn about compile-time computation, and
more about back quoteing in Macros. I glanced throug 'On Lisp'
but there are very little tutorial about macros and backquoting.

Thanks.

Backquoting kind of confuses me. ' ` , ,@ etc.
From: Raffael Cavallaro
Subject: Re: An intresting "Recursive" Macro.
Date: 
Message-ID: <aeb7ff58.0305181749.42f0f270@posting.google.com>
"Franz Kafka" <Symbolics _ XL1201 _ Sebek _ Budo _ Kafka @ hotmail . com> wrote in message news:<··················@news02.roc.ny.frontiernet.net>...
> BTW, where would I learn about compile-time computation, and
> more about back quoteing in Macros. I glanced throug 'On Lisp'
> but there are very little tutorial about macros and backquoting.


Try:

_ANSI Common Lisp_, by Paul Graham - Chapter 10: Macros.

_On Lisp_ is a much more advanced text (hence the subtitle, _Advanced
techniques for Common Lisp_. It assumes that you're already a
competent lisp hacker, and moves on from there. _ANSI Common Lisp_ is
an introductory text that teaches Common Lisp from the ground up, and
so, has a more tutorial feel.

Also, try David Lamkins' on line book _Successful Lisp_. The Macro
tutorial chapter is at:

<http://psg.com/~dlamkins/sl/chapter03-08.html>




Raf
From: Franz Kafka
Subject: Re: An intresting "Recursive" Macro.
Date: 
Message-ID: <5zyxa.7611$jx1.2198@news01.roc.ny.frontiernet.net>
>
> ;; Tested under Genera:
> ;;   1.) It compiles without bombing out.
> ;;   2.) It has not been confirmed to be ANSI. :)
> ;;   3.) Shows the power of Lisp Macros in a Toy-way ;)
>
>

It get's even more intresting:

1.) if you macroexpand or macroexpand-1 the worm
     you get code.
2.) if you try si:macroexpand-all on the worm the
     machine crashes :(
3.) so I figure, but could be wrong, it will run in ANSI Lisp
     but if you try to Code Walk the form to fully expand
     the macro you can't -- could be wrong.
4.) the macro always termantes for resonalble values of
     max-worms.
5.) the macro is not really resurive -- it genrates Lisp code
     that calls the macro recursivelly -- ow my head hurts trying
     to get around that one.

It's fun to play /w micros -- if only I knew more about how
they work.

But, boy are they powerful, and cool 2.
From: Kaz Kylheku
Subject: Re: An intresting "Recursive" Macro.
Date: 
Message-ID: <cf333042.0305191310.326db4f@posting.google.com>
"Franz Kafka" <Symbolics _ XL1201 _ Sebek _ Budo _ Kafka @ hotmail . com> wrote in message news:<··················@news01.roc.ny.frontiernet.net>...
> ;; A recursive macro that demonstrates Lisp's ability
> ;; to write Lisp code. :)
> 
> (defmacro worm (&optional (max-worms 50))
>    (let ((fname (gensym)))
>       `(progn
>                   (defun ,fname ()
>                       (format t "~&Worm Number: ~d" ,max-worms))
>                   (if (= ,max-worms 0)
>                                                   t
>                                                   (worm (- ,max-worms 1)))


You don't have a recursion termination test in the macroexpansion!

To write a recursive macro you need something like this:

 (defmacro recursive (&rest args)
   (if (terminating-condition args)
     `(terminating-form)
     `(non-terminating-form ... (recursive ,(divide-and-conquer
args)))))

In other words, there has to be a macroexpansion-time check which will
stop the expansion by reducing to some case whose expansion does not
include another invocation of the same macro.

A Lisp implementation which tries to fully expand your macro will run
into infinite recursion and fail.

It can only work on Lisps that have lazy macroexpansion; meaning that
they leave the embedded macro call where it is, and don't expand it
until it is actually evaluated at run-time. Then your run-time
terminating condition may actually rescue the macro problem by fluke.