[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: #,

What can be done to allow load-time evaluation in a general fashion is
this.  (This has been implemented in Maclisp.  I won't say how because
it is a dirty kludge and was then specialized to a particular purpose.)

Provide the user with some means by which he can get load-time evaluation
performed to provide some object, no matter where it is in whatever
structure is being "dumped", by virtue of having some symbol (of HIS
choosing) as the car of a list.  (The CADR being the form which gets
evaluated at load time, for instance, although you might not want to
maintain that restriction.)

Then, the user is free to provide how to handle:
   (1)  What to do when the form is encountered by the compiler as a
form to be compiled, by defining some sort of compiler-macro or
optimizer or rewrite rule or whatever we have for that (which we
should also define).
   (2)  What to do when the form is encountered by the evaluator.
Since these forms are typically produced during compilation (by virtue
of the reading being done by the compiler, something which the user
should be able to determine [yet another thing to define]), this could
be considered an error, or the function could be a macro which quotes
itself, effectively causing the object to be self-evaluating.

So, for example, if this worked by virtue of the symbol having a
non-null :load-time-evaluation-form property, one might implement the
Maclisp SQUID form as follows:

;SQUID, "Self Quoting Internal Datum", has as its value a marker which
; you list around a form which should be evaluated at load time.  THe
; form is otherwise treated as being self-evaluating.
(defvar squid
  (copysymbol 'squid))

;Tell the compiler/assembler about the marker.
(putprop squid t :load-time-evaluation-form)

;Define how such a form compiles and evaluates:
(defun squid-quoter (form)
   (list 'quote form))

;I guess the following is probably wrong for common-lisp but anyway:
(fset squid '(macro . squid-quoter))

Then, the code for #, could simply do
	(if *reading-for-compilation*
	    (list squid (read))
	    (eval (read)))

"*reading-for-compilation*" should probably be
"*reading-for-external-compilation*" to distinguish it from the case
when the compiler is compiling directly to core.
Of course another way to do this is to have a flavor or
extend/message-passing system and simply define the right messages to
interface to the compiler and evaluator.
If you try to generalize this too much you run into problems
differentiating your runtime and compile-time environments;  for
example a macro which contains pointers to datastructure which should
be created with a special load-time-eval construct, but it can be used
both by the interpreter and the compiler.  Having the compiler not
bash the runtime environment with macro definitions it is compiling
(but save the definitions away and expand them otherwise) alleviates
this, but only for the single-file compilation.  There are potentially
other subtleties which make the read switch inadequate, such as having
a single textual definition which both needs to be compiled to a file
and stored in core (the traditional macro definition bashing the
runtime environment, for example, but this might arise in other ways).

Anyway, the reason i brought all this up is that we have played some
with writing, saving, and referring to nodes in semantic networks
here, and that is the sort of thing which "users" might try to do.
[JonL and/or Guy can testify to the Maclisp hacking in this regard
from variously the OWL, LMS, XLMS, and Brand-X systems, each of which
implemented yet another representation scheme and found the Lisp
primitives inadequate.]