Re: Lisp2Perl - Lisp to perl compiler

From: Joe Marshall (jrm_at_ccs.neu.edu)
Date: 01/27/04


Date: Tue, 27 Jan 2004 13:10:40 -0500

Pascal Costanza <costanza@web.de> writes:

> OK, I have checked my email archive to see what the issue was. Here it
> is: In MzScheme, there is obviously no way to access run-time values
> at compile time / macro expansion time. (I hope I have gotten the
> terminology right here.)
>
> This means that you can't say this:
>
> (define a 1)
> (define-macro (foo x) `(+ ,a ,x))
> (foo 2)
>
> This will result in a "reference to undefined identifier" error,
> because the foo macro doesn't see the a reference.

(define a 1)

(define-syntax foo
  (syntax-rules ()
   ((foo x) (+ a x))))

(foo 2) => 3

> In my implementation of dynamically scoped functions in Common Lisp, I
> make use of this collapsing of stages in order to be able to redefine
> existing functions as dynamically scoped functions, without changing
> their defined behavior. See my paper for an example how I turn a CLOS
> generic function into a dynamically scoped one.

I can see what you are doing. You're hijacking the dynamic scoping
mechanism of special variables to simulate dynamically scoped
functions. To do this, you need a mapping between functions and
unique special variables, and that is kept in the hash table held in
*DYNSYMS*. Now at compile time, if you encounter a DEFDYNFUN form,
you look in the table for the mapping and generate code that indirects
through the special variable.

At runtime, though, you want to be able to change a regular function
into a dynamic one should you so desire.

There's no problem with doing this with Matthew's module system.

> Even if I can go only forward in time, I like the fact that I can
> change the decisions I have made in the past. It escapes me why this
> should be an evil thing to do in programs.

That's not a problem. What is a problem is when you attempt to change
decisions in the future. It doesn't work in Common Lisp, and it
doesn't work in Matthew's system. Let me illustrate where the problem
crops up in both.

I have a `dotnet' interface layer that works by hacking the
macro-expansion facility to change identifiers like

    System.Reflection.AssemblyName.class

into forms like

    (clr/find-class 'system 'reflection 'assemblyname)

Part of the macro has to recognize identifiers with dots in them and
split them, and depending on where the dots are expand them in
different ways:

Foobar.Baz => (clr/find-static-method 'foobar 'baz)

.quux-field$ => (instance-field-getter 'quux-field)

(setf .quux-field$) => (instance-field-setter 'quux-field)

As should be obvious, utility functions such as `EMBEDDED-DOT-P' and
`SPLIT-ON-DOTS' *must* be present before we can expand the macros.
There is simply no way to get around that! When compiling a
*different* file that uses this macro, you *must* ensure that the file
that defines EMBEDDED-DOT-P is loaded first. This is a compile-time
dependency, but this dependency must be maintained.

It often happens that you accidentally introduce these dependencies
through incremental editing of files: you load up the compiled files,
edit some code, recompile that file, edit some more, do more
recompiles etc. At some point, you decide to recompile from scratch,
but all hell breaks loose because you added a macro whose expansion
depends on code that is compiled *after* the macro is used. It only
accidentally worked during development because you never attempted to
recompile the utility file that expanded the macro, only those files
that used it.

What Matthew's module system does is ensure that code that the macro
*uses* at compile time is in scope at compile time and not
accidentally obtained from the runtime environment. Errors such as
the above are caught sooner because incremental compilation and whole
world compilation are treated more uniformly.



Relevant Pages

  • Re: Whats up with Scheme macros?
    ... "Defines name as a macro by associating a macro function with that name ... (defmacro foo () ... But the value of x is needed at compile time, ... they happen for a reason. ...
    (comp.lang.lisp)
  • Re: silly: "spel" instead of "macro"
    ... but the macro form could not have. ... > Couldn't another implementation decide to compile before executing ... an instance of fooclass does not have a readable print ... 0-> The symbol FOO ...
    (comp.lang.lisp)
  • Re: Rebuilding functions at run-time
    ... (deftemplate foo () ... But, AFAIK, this can't be a macro, since it will be expanded at macro- ... Another option could be compile, ... (let ((string initial-string)) ...
    (comp.lang.lisp)
  • Re: modifying array access syntax
    ... I published recent speculation on the ARRAY ... > are in fact remnants of the property lists of these Lisp-N ... these that were meaningful at compile time (FEXPR, FSUBR, and MACRO ...
    (comp.lang.lisp)
  • Re: warn if not top-level?
    ... >> called by run-tests contains old macro expansions (and may simply delay ... you have to recompile ... > than COMPILE, based on some prior discussions I've found. ... (loop for arg in test-data ...
    (comp.lang.lisp)