On Mon, Jan 23, 2012 at 11:23 AM, Imran Rafique <im...@rafique.org> wrote:
> I think the one thing which does bother me though, is the lack of a separate
> macro-expansion phase. Sure, fexpr's give you what macro's do, at runtime.
> But one of the key things which make me feel comfortable in any lisp is the
> knowledge that I can effectively re-arrange the syntax of certain operation
> sequences to forms that I prefer.
You call for a separate macro-expansion phase, but what you really
want is the runtime performance. I believe it is possible to achieve
this runtime performance without the ugliness that would be introduced
with CL style macros. Let me explain the ugliness first, and then the
IMHO, CL style macros would be ugly in picolisp because there is no
way to tell code from data. Suppose you have a quoted list beginning
with a symbol defined as a macro. If it is expanded as a macro, you'll
never feel safe when quoting a list that's supposed to be data, but if
it's not expanded you won't be able to use quoted lists to pass code
into other functions, at least not without feeling the agony of the
supposed runtime penalty. In a language where lambda is quote, this
would be very sad indeed. There are several additional ugliness
aspects I won't mention for the sake of brevity, just think CL vs
Now, the proposed solution: Picolisp style FEXPRs have the ability to
not only read the argument list unevaluated, but also modify it. These
modifications are preserved in the loaded code until next time the
function is called from the same place in the code. This is how 'job'
environments work. Picolisp style FSUBRs (a C compiled function) on
the other hand can read and modify the entire form. This allows them
to modify not only the argument list (the cdr of the form) but also
the functional expression of the form (the car). I propose this
ability is given to FEXPRs as well. A macro would then be a function
that alters the car and cdr of it's own form and then evaluates it.
This type of macro will work inside quoted code without disturbing
quoted data, since it will expand the first time it is executed.
I believe this method would preserve the simplicity of picolisp, since
macros are not introduced explicitly - only the possibility of rolling
your own macro engine is added. This addition to the language would
also open up many interesting possibilities other than macro engines.
I have used this technique before (in picolisp, with an ugly
workaround,) to achieve some things with this type of... let's call it
"lexical reflection". In short, it would give FEXPR's a power they now
lack compared to FSUBR's.
If this ability is given to FEXPR's, anyone could make their own
'defmacro'. Macro expansion would still occur once every runtime, but
not more than once. Also, unnecessary macro expansions (of forms that
won't be executed anyway) will never occur.
Example of a form-altering function (not tested, of course):
(de loop X (set *FORM 'prog) (con *FORM (apply circ X)) (eval *FORM))
This defines an eternal loop as a macro expanding to a prog carrying a
circular body. I don't necessarily propose this feature is introduced
with a variable *FORM as in the example above, but any other way I can
think of seems just as ugly.