[Larceny-users] Ticket 638

Andre van Tonder andre at het.brown.edu
Tue Apr 21 09:19:03 EDT 2009


This ticket describes a conciously chosen feature.

On Mon, 20 Apr 2009, Lynn Winebarger wrote:

>  (import (for (rnrs) run expand)
>          (rename (only (rnrs base) cons) (cons kons)))
>
>  (free-identifier=? #'cons #'kons)
>
>  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

This is a concious design choice in the implementation of FREE-IDENTIFIER=?
The fact that this code does not work in Larceny shows that the code is not 
R6RS-compliant.  That it works in PLT and Ikarus just shows that their 
implementors chose not to worrry about imposing R6RS portability for reasons of 
their own.

          A syntax error is raised if free-identifier=? succeeds
          but either argument is outside its declared level.  This is sufficient
          to ensure that literals such as ... in syntax-case, DEFINE,
          BEGIN, etc., in bodies, UNQUOTE, etc. in quasiquote, etc., are used at
          the correct level.  See the examples below for more discussion, and for
          an explanation of why the levels should not be checked if the
          comparison fails.

The fact that some implementations do not impose this restriction is irrelevant. 
What is relevant is that R6RS allows and in fact encourages implementations 
(present or future) to check phases of references, and one of goals of my 
expander was to try to ensure maximum portability to other R6RS implementations 
by doing as many checks as possible.


The following discusses this further and was taken from 
http://www.het.brown.edu/people/andre/macros/december-27-07/examples.scm


    ;;=================================================================
    ;;
    ;; Phase checking for literals and free-identifier=? uses:
    ;;
    ;; R6RS does not say if these operations count as references,
    ;; but does require importing of literals such as ... and _
    ;; into the appropriate phase.  To ensure maximal portability,
    ;; a good implementation should have a liberal interpretation of
    ;; what a reference is, and check literal phases.
    ;; We do so by checking that the arguments of free-identifier=?
    ;; are both in phase when the result of the comparison is #t
    ;; (for examples why, see below).
    ;; For ensuring that uses of literals are in phase, this is sufficient
    ;; but may be more than necessary.  However, we are within our R6RS
    ;; rights to be more restrictive, and in this case more is
    ;; better for maximal portability checking.
    ;;
    ;;=================================================================

    ;; This shows why we should only test that the arguments of free-identifier=?
    ;; are in phase when the comparison succeeds.  The expander should complain
    ;; about the wrong phase of ..., but should not complain about the phase of
    ;; LIST in the template, even though LIST is also compared to see if it
    ;; is bound to R6RS ... during expansion.

    ;;(library (foo)
    ;;  (export)
    ;;  (import (except (rnrs base) ...)
    ;;          (only (rnrs syntax-case) ...))  ;; .. is in wrong phase
    ;;  (define-syntax list-macro
    ;;    (syntax-rules ()
    ;;      ((_ x ...) (list x ...)))))
    ;;
    ;;   Attempt to use binding ... in library foo at invalid meta level 1.
    ;;   Binding is only available at meta levels: 0

    ;; More examples:

    (library (foo)
      (export test)
      (import (rnrs base))
      (define-syntax test
        (syntax-rules (car)
          ((_ car) #t)
          ((_ k)   #f))))

    ;; The literal CAR is used in the wrong phase:
    ;;
    ;;(library (bar)
    ;;   (export)
    ;; (import (for (rnrs base) (meta 21))
    ;;          (foo))
    ;;  (test car))
    ;;
    ;;    Attempt to use binding car in library bar at invalid meta level 0.
    ;;    Binding is only available at meta levels: 21

    ;; This is not a literal use, so no problem.

    (library (bar)
      (export)
      (import (for (rnrs base) (meta 21))
              (foo))
      (test cdr))

    ;; Here the literal is in the wrong phase at the definition site:

    (library (foo)
      (export test)
      (import (except (rnrs base) car)
              (for (only (rnrs base) car) (meta 21)))
      (define-syntax test
        (syntax-rules (car)
          ((_ car) #t)        ; is this a reference?
          ((_ k)   #f))))

    ;; The problem is detected as soon as we try to use it:

    ;;(library (bar)
    ;;  (export)
    ;;  (import (rnrs base)
    ;;          (foo))
    ;;  (test car))
    ;;
    ;;    Attempt to use binding car in library foo at invalid meta level 0.
    ;;    Binding is only available at meta levels: 21

    ;; We will not detect the problem if we do not use the literal, though.

    (library (bar)
      (export)
      (import (rnrs base)
              (foo))
      (test cdr))     ;==> expands without problems

    ;; To summarize, the arguments of free-identifier=? are only
    ;; required to be in phase when the comparison succeeds.

    (library (foo)
      (export test1 test2)
      (import (except (rnrs) car)
              (for (only (rnrs) car) (meta 21)))
      (define-syntax test1
        (lambda (form)
          (free-identifier=? (syntax car) (syntax cdr))))
      (define-syntax test2
        (lambda (form)
          (free-identifier=? (syntax car) (syntax car)))))

    (import (foo))
    (test1)  ;==> #f

    ;;(test2)
    ;;
    ;;    Attempt to use binding car in library foo at invalid meta level 0.
    ;;    Binding is only available at meta levels: 21 22

    ;; Another example, similar in spirit to the first ... example.

    ;;(library (foo)
    ;;  (export)
    ;;  (import (rnrs base)
    ;;          (for (prefix (only (rnrs base) quasiquote) meta-) (meta 21)))
    ;;  `(meta-quasiquote 1))
    ;;
    ;;   Attempt to use binding meta-quasiquote in library foo at invalid meta 
level 0.
    ;;   Binding is only available at meta levels: 21

    ;; Out of phase uses of the literals DEFINE, BEGIN, etc., in
    ;; bodies are detected in the same way.

    ;;(library (foo)
    ;;  (export)
    ;;  (import (except (rnrs base) define)
    ;;          (for (only (rnrs base) define)))  ; imported but for no levels
    ;;  (define x 1)
    ;;  (display x))
    ;;
    ;;    Attempt to use binding define in library foo at invalid meta level 0.
    ;;    Binding is only available at meta levels:








More information about the Larceny-users mailing list