H. Justin Coven recently inquired about ideas for self-modifying code,
particularly by using "apply" in LISP. The question was raised in the
context of systems that learn. What follows is (only) my opinion,
based on a lot of writing LISP programs that write other programs, but
only a little work on learning systems.
In the context of learning systems, "apply", I think, is handy for
simple situations, but awkward to use in complex situations. It is
useful to think specifically about the best form in which to use the
modified code, and there are usually many options, including using the
modified code in a different process from that which generated it.
This gets us quickly to thinking generally about how to deal with
programs generated by other programs.
The best form for programs generated by other programs depends upon
the circumstances in which the generated program is to be used. The
range of circumstances is large, from compilation to transient
generation and use. Deciding what the actual circumstances are may be
harder than it appears to be at first glance; there are apt to be
more choices than you originally think you have.
One issue is whether the generated program is to be in the same
language as the generator. If the generated program is in a different
language, it is usually necessary (especially if the generated program
is source code which is to be compiled) to write it to a file. It may
be useful to generate the entire program as a structure in active
memory before printing any of it, however. I have used LISP and C to
write RS274-D programs, for example, and find it useful to proceed
this way. I sometimes use LISP to write C, which I then compile, for a
second example.
A second issue is whether the generated program is to run in the same
process as the generator. In this case the generated program must be
in the same language as the generator or in a language (tcl, for
example) for which the generating language has an interpreter.
Three criteria for making a decision on how to implement when there is
a choice are programming difficulty, timing, and program persistence.
1. Difficulty - If generating the program is difficult, implement the
easiest way first. Reconsider other choices after you've got the easiest
method working.
2. Timing - If the generated program is to be used many times or if it
is apt to take a long time run once, it may be a good idea to compile
it to minimize the time it takes to run it. Of course LISP is great in
this regard, since you can write a program, compile it, load it, and
run it - bang, bang, bang. On the other hand, if you want a small fast
program as output, generating in a lower level language (C, for
example) may be a good idea. I recently wrote a LISP program which
read data from a file and ran a long time (many days in some runs);
call it program A. I then then wrote a LISP program which read the
data used by program A and generated C-language structures; I wrote by
hand the C-language code which used the structures. The structures and
the hand-written code compiled into a program (call it B) which did
exactly the same thing as program A. Program B (even with all the data
compiled in) required about 1/20 of the memory used by program A, and
B ran about 40 times as fast as A.
3. Persistence - If the generated program is to be kept around for
repeated use, it is usually useful to write it to a file.
Tom Kramer
kramer@cme.nist.gov
|