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)))
>
>
--