From: David R. Sky
Subject: Re: Looking for specific feedback: Story of Mac
Date: 
Message-ID: <Pine.LNX.4.61.0412121054250.1476@viper.wapvi.bc.ca>
Thanks pascal. I just don't understand the code you wrote yet. David

On Tue, 30 Nov 2004, Pascal Bourguignon wrote:

> "David R. Sky" <ยทยทยท@viper.wapvi.bc.ca> writes:
>
>> I have learned how to write a function in Lisp, not a macro
>> yet. (Which I had been wondering about.) Which is maybe why I did not
>> at all understand your Mac metaphor. David
>
> If you know how to write a function, you know how to write a macro:
>
> (defun repeat-f (body-and-until)
>    (let ((until (car (last body-and-until)))
>          (body  (butlast body-and-until))
>          (tag   (gensym)))
>      (unless (eq 'until (first until))
>        (error "Last for of a REPEAT body must be: (UNTIL condition)"))
>      (append (list 'tagbody tag
>                    (cons 'progn body)
>                    (list 'if (list 'not (second until)) (list 'go tag))))))
>
> (repeat-f '((print i) (incf i) (until (> i 10)))) ==>
>   (TAGBODY #:G1339 (PROGN (PRINT I) (INCF I)) (IF (NOT (> I 10)) (GO #:G1339)))
>
> Here you have a function that takes some argument that look like lisp
> code, and that return a list that look like lisp code.  The
> interesting part is, this function could be used by the compiler to
> generate this code automatically for you when you write stuff like:
>
>    (repeat
>        (print i)
>        (incf i)
>     (until (> i 10)))
>
> You only have to write:
>
> (defmacro repeat (&body body-and-until)  (repeat-f body-and-until))
>
> Or, of course, you could substitute and avoid the function:
>
> (defmacro repeat (&body body-and-until)
>    (let ((until (car (last body-and-until)))
>          (body  (butlast body-and-until))
>          (tag   (gensym)))
>      (unless (eq 'until (first until))
>        (error "Last for of a REPEAT body must be: (UNTIL condition)"))
>      (append (list 'tagbody tag
>                    (cons 'progn body)
>                    (list 'if (list 'not (second until)) (list 'go tag))))))
>
> And finally, all this append-ing, list-ing and cons-ing could be
> hidden using backquote and comma:
>
> (defmacro repeat (&body body-and-until)
>    (let ((until (car (last body-and-until)))
>          (body  (butlast body-and-until))
>          (tag   (gensym)))
>      (unless (eq 'until (first until))
>        (error "Last for of a REPEAT body must be: (UNTIL condition)"))
>      `(tagbody ,tag
>            (progn ,@body)
>            (if (not ,(second until)) (go ,tag)))))
>
> Then you can check what the compiler will use when you write a repeat:
>
> (macroexpand-1 '(repeat (print i) (incf i) (until (> i 10)))) ==>
>  (TAGBODY #:G1340 (PROGN (PRINT I) (INCF I)) (IF (NOT (> I 10)) (GO #:G1340)))
>
>

--