On Mon, 2009-04-20 at 22:04 -0400, Lynn Winebarger wrote: > This ticket is pretty interesting: > > % cat temp2.sps > (import (for (rnrs) run expand) > (rename (only (rnrs base) cons) (cons kons))) > > (free-identifier=? #'cons #'kons) > % ./larceny --r6rs --program temp2.sps > > Syntax violation: invalid reference > > Attempt to use binding of cons in library (program~19XamJ~2) at > invalid level -1. Binding is only available at levels: 0 1 2 > > Evidently this should evaluate to #t according to the PLT test suite.
For implicit phasing systems, such as Ikarus and Ypsilon, a result of #T makes sense because any phase level specifications are ignored and `cons' and `kons' are bound to the same thing at every phase. But for explicit phasing systems, such as Larceny and PLT, I don't think a result of #T makes sense because `cons' and `kons' are unbound at phase -1 and unbound identifiers are compared according to their spelling. If they are supposed to be bound, that's either implicit phasing or confusing syntax template semantics. I've encountered this weirdness with PLT syntax templates before. I found it quite confusing and inconsistent that PLT's syntax templates' identifiers are apparently not always (- phase 1) (even more explicit phasing complications to scare people away from learning macros, yay!). I think it's a bug in PLT because my code shown below has a syntax template at phase 0 and the identifiers in it are certainly at phase -1 (because I made that the only possibility) and it works on PLT, which is inconsistent with the PLT test suite program above. > First, if it isn't clear, this is occuring because Andre's system is > resolving the reflected identifier in the syntax form, regardless of > whether the form is being evaluated on the right hand side of a syntax > binding form (define-syntax etc). That's why it reports the > identifier being desired at level -1. I think Larceny's phase mismatch detection is very preferable to allowing separate namespaces (that would be very unSchemely) for different phases such that `cons' would be allowed unbound at phase -1 but bound at the phases it's imported for. And this detection is consistent with the fact that R6RS requires preventing importing the same name but different bindings at different phases. > There are multiple issues: > 1) The syntax violation is getting triggered too early. How can you tell? > There's an > echo of Will's complaint that R6RS requires compiling programs with > obvious errors to give error messages at run-time That temp2.sps is being compiled and run in the same process, so how can you tell when the error is happening? I think it probably actually is happening at expand-time. > 2) The binding is getting resolved too early. It shouldn't be > resolved until it appears on the right hand side of a syntax binding > form. Consider whether the following program should produce 'a or 7: Because Scheme is lexically scoped and maintaining that is a primary purpose of R6RS syntax templates, it's obvious to me that `foo' should be bound to a syntax object representing the identifier `x' from the lexical scope where that identifier occurs, and that identifier refers to the `x' imported from `(defines x)'. > (library (defines x) (export x) (import (rnrs)) > (define x 7)) > > (library (defines foo) > (export foo) > (import (rnrs) (rnrs syntax-case) (for (defines x) (meta -1))) > (define foo (syntax x)) > ) > > (library (expands foo) > (export foo-expander) > (import (for (rnrs) run expand) > (for (rnrs syntax-case) run expand) > (for (defines foo) run expand)) > > (define x 'a) > (define-syntax foo-expander > (lambda (x) > (syntax-case x () > ((_) foo)))) > ) > > (import (expands foo)) > (foo-expander) > > This test would imply 'a is the right answer. Ikarus, Larceny, PLT, and Ypsilon (which all have different implementations of R6RS macros) all say the answer is 7. > That preserves > referential transparency at the site of the macro definiton, even > though the identifier object is constructed outside that context. I don't think it would preserve referential transparency because the value of `foo' is a syntax object representing the identifier `x' from the lexical scope where that identifier occurred. Referential transparency means an expression can be replaced with its value without changing the semantics. If you replaced the `foo' expression with its value, it would be like importing the `x' from `(defines x)' with a renamed name and referring to that renamed name. I certainly want to be able to make helpers like in the below example and know what their output is going to refer to. (This is also the code with the PLT syntax template phase level inconsistency I mentioned above). $ cat help/do-it.sls #!r6rs (library (help do-it) (export do-it) (import (rnrs)) (define (do-it x) (list x x))) $ cat help/helper.sls #!r6rs (library (help helper) (export helper) (import (rnrs) (for (help do-it) (meta -1))) (define (helper x) (quasisyntax (do-it (unsyntax x))))) $ cat use-help.sps #!r6rs (import (rnrs) (for (help helper) expand)) (define do-it 'different) (define-syntax m (lambda (stx) (syntax-case stx () ((_ x) (helper (syntax x)))))) (write (m 1)) (newline) $ ikarus --r6rs-script use-help.sps (1 1) $ larceny -path . -r6rs -program use-help.sps (1 1) $ plt-r6rs ++path . use-help.sps (1 1) $ ypsilon --sitelib . use-help.sps (1 1) $ IIUC, you're saying the syntax object returned from `helper' should refer to the `do-it' in the program. That would defeat the whole point of hygienic macros. > 3) It doesn't make a lot of sense to have free-identifier=? if you > can't create a free identifier without triggering an expand time > error. You can do that. Larceny's error is happening because the free identifiers have imported bindings in scope but not at the right phase level and so it's preventing separate namespaces from existing. -- : Derick ---------------------------------------------------------------- _______________________________________________ Larceny-users mailing list Larceny-users@lists.ccs.neu.edu https://lists.ccs.neu.edu/bin/listinfo/larceny-users