On Mar 26, 11:55 pm, Abdulaziz Ghuloum <[email protected]> wrote:
> Here, you're talking about the visibility/scope/meaning of
> identifiers (those that are imported and those that are
> defined with define/define-syntax).  The term "phase
> separation" is ambiguous as it pertains to other issues like
> when, why, and how many times libraries are expanded/invoked.

Ok, I was indeed unsure about the terminology.

> > 1. full phase separation (mzscheme, Larceny); there is an
> > infinite tower of metalevels, and you are forced to specify
> > at which phase you want to import the names;
>
> The number of meta levels is always bounded by the number of
> things you type in the import-for clause.  It's always finite
> in the mzscheme/larceny world.  In Ikarus however, imported
> identifiers are available at all levels.

Yes, I should have written "potentially infinite" in the sense
that you can nest macros arbitrarily deep and in principle
you can reach any level.

> > 2. partial phase separation (Ikarus); importing a name
> > imports it at all levels;
>
> > 3. no phase separation (REPL of Ikarus and Ypsilon).
>
> > The rationale for 1 is that some people (not me) want the
> > freedom to use different languages at different levels.
>
> The rationale for 1 is in Matthew Flatt's "Composable and
> Compilable Macros" paper.  I don't recall there is any mention
> of "different languages at different levels" in that paper.
> The main rationale that I get is to control side effects that
> happen at compile time (see the zoo examples).

I was not convinced by that example, but now I have no
time to discuss it further. I was referring to Eli Barzilay
who said many times explicitly that he wanted the ability
to use different languages at different levels and this
is used in PLT Scheme. I am not convinced by Eli's point
either.

> Nop!  The compiler does NOT have access to helper functions
> defined in the same compilation unit until the entire unit is
> expanded. Consider a library containing:
>
> (define t (make-table ---))
> (define-syntax m (lambda (x) --- use t ---))
> (initialize-table! t)
>
> At the time the code for m is expanded, the expander has not
> yet finished expanding the library, and has no knowledge of
> the initialization code.  If we allow the use of t, we'd be
> hosed for using an uninitialized table.

Yes, than we would need to write

(define t (make-table ---))
(initialize-table! t)
(define-syntax m (lambda (x) --- use t ---))

and then people would complain, because when changing the table
at runtime they would see no effect in the macro.
I thought about this, I am not sure if one should put
restrictions and accept only definitions involving
immutable objects (and therefore the same both
at compile-time and run-time).

Another issue would be the following:

(define today (current-date))
(define-syntax some-macro (lambda (x) --- use today ---)
(define some-function (lambda (x) --- use today --)

When using some-macro we would get the compilation date
(possible months ago) and when using some-function we
would get the date of execution. However, this
happens even in current Scheme, if you define a
macro depending on the current date.

So, I realize evaluating names both and runtime and at
compile time could give to surprising results and people
should be warned about the traps and pittfalls.

> > Instead, R6RS-compatibility forces us to put the auxiliary
> > functions in an auxiliary module and to import them.
>
> No.  What forces us is the desire to be able to fully expand
> and compile each library without having to also evaluate it.

I am trying to understand all the reasons
why we do not want to evaluate each library.
Is there more than the effects we discussed before?

For instance a

(define something (read))

when evalued at compile-time would stop the compiler,
read an expression from stdin and continue; when evalued
at run-time it could read a completely different expression,
so it would be a foolish idea for sure.

Reply via email to