Ok,
So, when working with trying to understand how to implement and work with hygiene, one of the things that I have discovered is that often the specification and/or documentation of stuff related to hygiene contain seemingly random and stupid things. Later on, I have often had to realize the hard way why it was like that.
I wonder if I have come to another situation like that. SRFI-83 (R6RS library syntax) contains a seemingly random and ugly limitation; It doesn't have anything like BH's syntax-begin. What you can do instead is to specify whether you want to import modules for run-time or compile-time. Importing srfi-1 for use by macros could look like this in BH:
(syntax-begin (import srfi-1))
Or like this in SRFI-83:
(import (for srfi-1 expand))
The two rows above are roughly equivalent, but as I understand it there is no SRFI-83 equivalent of
(syntax-begin (syntax-begin (import srfi-1)))
That is, importing things for use in the macro expansion expansion phase. So far, I have thought that this is a stupid thing, needlessly limiting what can be done, plus it's not as theoretically elegant.
But I have realized that there might be a point in doing it like SRFI-83: It is an elegant way of limiting imports to the first and second level of the syntactic tower.
Even though you cannot (or at least should not) limit how high the syntactic tower can be, you can limit all levels above two to not include any other modules, thus limiting them to the standard library. You would also need to remove the possibility to have state in levels higher than the first. (For instance (syntax-begin (define state-var #f))). In practise this would mean to remove syntax-begin and replace it with a less powerful construct like the one in SRFI-83, let's call it import-for-syntax.
I hope this limitation would allow BH to only have at most two instances of each module at any given time. (Assuming that the standard library doesn't have any state)
Consider this example:
a.scm: (import b)
(b-mac)
b.scm: (import c)
(define-syntax b-mac (sc-macro-transformer (lambda (form env) `(c-mac))))
c.scm: (import-for-syntax d)
(define-syntax c-mac (sc-macro-transformer (lambda (form env) (my-not #t))))
d.scm: (define (my-not bool) (if bool #f #t))
When macro expandng (compiling) modules, the module system would conclude to do it in the order d, c, b, a. Compiling d, it would compile two functions, say d#my-not and d~#my-not. Compiling c, it would compile the c-mac macro (only one instance of it). c-mac would use the d~#my-not function. Similarly for b, it would compile one instance of b-mac. When compiling a, it would invoke b-mac, which would expand to (c-mac), leading to an invocation of that macro, which would call the compile-time version of my-not.
Doing it this way, it would be possible to allow two modes of compilation, one for releases, where only run-time versions of definitions are included, and all macro information is stripped, and one for development, which also contains compile-time definitions, macros, and other module information like dependencies and exported variables and macros.
Does this make sense? To me, this seems like a good compromise between correctness, power and speed. I can't think of any practical case where this less powerful way of doing things isn't powerful enough, although sometimes helper modules for containing macro state would be needed.
/Per
Afficher les réponses par date
Nah.. That wouldn't work. Nevermind.
It does (with some modifications) solve the most practical problem, that is that a module when compiled will never change the behavior of other compilations or the run-time system, but it doesn't do it the Right Way syntactic tower wise.
/Per
On Mon, May 25, 2009 at 1:06 PM, Per Eckerdal per.eckerdal.trash@gmail.com wrote:
Ok,
So, when working with trying to understand how to implement and work with hygiene, one of the things that I have discovered is that often the specification and/or documentation of stuff related to hygiene contain seemingly random and stupid things. Later on, I have often had to realize the hard way why it was like that.
I wonder if I have come to another situation like that. SRFI-83 (R6RS library syntax) contains a seemingly random and ugly limitation; It doesn't have anything like BH's syntax-begin. What you can do instead is to specify whether you want to import modules for run-time or compile-time. Importing srfi-1 for use by macros could look like this in BH:
(syntax-begin (import srfi-1))
Or like this in SRFI-83:
(import (for srfi-1 expand))
The two rows above are roughly equivalent, but as I understand it there is no SRFI-83 equivalent of
(syntax-begin (syntax-begin (import srfi-1)))
That is, importing things for use in the macro expansion expansion phase. So far, I have thought that this is a stupid thing, needlessly limiting what can be done, plus it's not as theoretically elegant.
But I have realized that there might be a point in doing it like SRFI-83: It is an elegant way of limiting imports to the first and second level of the syntactic tower.
Even though you cannot (or at least should not) limit how high the syntactic tower can be, you can limit all levels above two to not include any other modules, thus limiting them to the standard library. You would also need to remove the possibility to have state in levels higher than the first. (For instance (syntax-begin (define state-var #f))). In practise this would mean to remove syntax-begin and replace it with a less powerful construct like the one in SRFI-83, let's call it import-for-syntax.
I hope this limitation would allow BH to only have at most two instances of each module at any given time. (Assuming that the standard library doesn't have any state)
Consider this example:
a.scm: (import b)
(b-mac)
b.scm: (import c)
(define-syntax b-mac (sc-macro-transformer (lambda (form env) `(c-mac))))
c.scm: (import-for-syntax d)
(define-syntax c-mac (sc-macro-transformer (lambda (form env) (my-not #t))))
d.scm: (define (my-not bool) (if bool #f #t))
When macro expandng (compiling) modules, the module system would conclude to do it in the order d, c, b, a. Compiling d, it would compile two functions, say d#my-not and d~#my-not. Compiling c, it would compile the c-mac macro (only one instance of it). c-mac would use the d~#my-not function. Similarly for b, it would compile one instance of b-mac. When compiling a, it would invoke b-mac, which would expand to (c-mac), leading to an invocation of that macro, which would call the compile-time version of my-not.
Doing it this way, it would be possible to allow two modes of compilation, one for releases, where only run-time versions of definitions are included, and all macro information is stripped, and one for development, which also contains compile-time definitions, macros, and other module information like dependencies and exported variables and macros.
Does this make sense? To me, this seems like a good compromise between correctness, power and speed. I can't think of any practical case where this less powerful way of doing things isn't powerful enough, although sometimes helper modules for containing macro state would be needed.
/Per
gambit-modules-list@iro.umontreal.ca