logo       

Re: New, from-scratch implementation of backquote.: msg#00073

lisp.clisp.general

Subject: Re: New, from-scratch implementation of backquote.

On Fri, 11 Apr 2003, Hoehle, Joerg-Cyril wrote:

> Date: Fri, 11 Apr 2003 13:22:31 +0200
> From: "Hoehle, Joerg-Cyril" <Joerg-Cyril.Hoehle@xxxxxxxxxxxxx>
> To: clisp-list@xxxxxxxxxxxxxxxxxxxxx
> Cc: kaz@xxxxxxxxxxxxxxxxxxx
> Subject: New, from-scratch implementation of backquote.
>
> Hi,
>
> I found the following thread from 1999 quite intriguing:
>
> Christopher R. Barry in cll on: quasiquote reference implementation
> http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&selm=87vh8hk0dj.fsf%402xtreme.net&rnum=8
> (defmacro defclass* (name supers slots &rest options)
> `(macrolet ((do-it ()
> `(defclass ,,name ,,supers ,,slots ,,@options)))
> (do-it)))

Interesting; basically this uses macrolet solely to obtain an extra
level of macroexpansion, so that the name, supers, slots and options
are all evaluated.

However, because defclass is a macro, this relies on evaluating the
forms at macroexpand time, so that their evaluated values can be stuck
into the defclass form itself.

So the expressions can only refer to functions and variables that
are available at that time.

> Now you can do something like:
> USER(15): (loop for i from 1 to 3
> collect (defclass* (intern (format nil "FOO-~D" i)) () ()))
> (#<STANDARD-CLASS FOO-1> #<STANDARD-CLASS FOO-2> #<STANDARD-CLASS FOO-3>)
> In CLISP-2.30, this gives
> *** - EVAL: variable I has no value

This is right because the lexcal variable i does not exist at the
macrolet expansion time. You see the (defclass* ...) construct can be
(and is) expanded before the (loop ...) is executed.

A macrolet construct cannot give you a different macroexpansion each
time you evaluate it; it's just a scoping mechanism for local macros,
not a dynamic macro mechanism. Local macros give you a way to hook into
the system's code walker, but that walk happens just once.

> For reasons I don't yet understand (I'm not even sure one can expect the
> do-it trick to work in all kinds of macroexpansion).
> A simple case works:
> > (defclass* (intern "FOO-1") () ())
> #<STANDARD-CLASS FOO-1>

Yeah, but this is at the top level and as such doesn't rely on any
lexical variables.

> BTW, the above thread is the one (from 1999) were I suggested a programmable
> interface to backquote: what you implemented now for CLISP!

I don't think that will help, because it's not a backquote problem.

To solve this problem you need the help of EVAL. Your loop must
actually construct the *source code* of a DEFCLASS construct into which
it has inserted all the right pieces, and then EVAL that source code
so that its effect takes place.

Example:

(loop for i from 1 to 3
collect `(defclass ,(intern (format nil "FOO-~D" i)) () ())
into defclasses
finally (eval `(progn ,@defclasses)))

We dynamically a list, a piece of data, which looks like:

((defclass FOO-1 ...)
(defclass FOO-2 ...)
(defclass FOO-3 ...))

Then we stick a PROGN in front and EVAL it as code, causing the classes
to be defined. The loop can be written so that it generates a
completely different list each time, using a different range of
integers and different base name for the symbol. Each time you call it,
it will generate some data and then evaluate it as code. Macros cannot
do that; they are expanded at compile time to produce their
substitution and then go away.

I will try the original trick with the new backquote, but I'm almost
certain that it won't work.

I should mention that the support for ,,@ actually does work in the old
backquote. The implementation notes are misleading.



-------------------------------------------------------
This SF.net email is sponsored by: Etnus, makers of TotalView, The debugger
for complex code. Debugging C/C++ programs can leave you feeling lost and
disoriented. TotalView can help you find your way. Available on major UNIX
and Linux platforms. Try it free. www.etnus.com


<Prev in Thread] Current Thread [Next in Thread>
Google Custom Search

News | FAQ | advertise