Re: [Scheme-reports] 5.3 Syntax Definitions Andre van Tonder (04 Jun 2011 00:52 UTC)
Re: [Scheme-reports] 5.3 Syntax Definitions Alex Shinn (04 Jun 2011 07:02 UTC)
Re: [Scheme-reports] 5.3 Syntax Definitions Andre van Tonder (04 Jun 2011 14:08 UTC)
Re: [Scheme-reports] 5.3 Syntax Definitions Alex Shinn (05 Jun 2011 09:41 UTC)
Re: [Scheme-reports] 5.3 Syntax Definitions John Cowan (05 Jun 2011 20:19 UTC)

Re: [Scheme-reports] 5.3 Syntax Definitions Andre van Tonder 04 Jun 2011 00:52 UTC

On Fri, 3 Jun 2011, Arthur A. Gleckler wrote:
>>
> It looks like there's a word missing here.  Perhaps add "in" after
> "undeferred?"
>
> I still find it confusing.

Sorry, I shot that off too quickly.  Better:

    An internal (syntax-)definition must not shadow any identifier
    whose binding (or lack of binding) in surrounding code has already affected
    the expansion of preceding portions of the body or of the (syntax-)definition
    itself.

If this constraint is violated, it means that one identifier is used with two
different meanings (bindings) in the same scope, which should be an error.

If this is confusing, it is probably because it depends on knowledge of the
expansion algorithm, which is not described in the WG1 document.  R6RS requires
a specific two-pass expansion.  The first pass discovers definitions and
expands and evaluates macros and the second pass expands deferred right hand
sides of variable definitions.  This allows uses of macros before they are
defined:

   (let ()
     (define (even n) .....odd....)    ; this is a procedure!
     (define-syntax odd ..........)
     .....)

This style seems to be somewhat unpopular, to say the least.  (Note that if both
EVEN and ODD were syntax-rules macros, there would be no problem.)

A single-pass left to right expansion is possible if we don't care to allow
this kind of forward use of macros.

Here is a bunch of examples of the kind of things that should be errors, from
my test suite:

    ;; This must give an error:

    ;; (let ()
    ;;   (define-syntax foo (lambda (e) (+ 1 2)))
    ;;   (define + 2)
    ;;   (foo))      ; Syntax violation: Definition of identifier that may have
    ;;               ; already affected meaning of undeferred portions of body: +

    ;; This gives no error:

    (let ()
      (define-syntax foo (lambda (e) (let ((+ -)) (+ 1 2))))
      (define + 2)
      (foo))         ;==> -1

    ;;(let ((x #f))
    ;;  (let-syntax ((foo (syntax-rules (x)
    ;;                      ((_ x y) (define y 'outer))
    ;;                      ((_ _ y) (define y 'inner)))))
    ;;    (let ()
    ;;      (foo x p)
    ;;      (define x #f)
    ;;      p)))          ; Syntax violation: Definition of identifier that may
have
    ;;                    ; already affected meaning of undeferred portions of
body: x

    ;;(let ((x #f))
    ;;  (let-syntax ((foo (syntax-rules (x)
    ;;                      ((_ x y) (define y 'outer))
    ;;                      ((_ _ y) 1))))
    ;;    (let ()
    ;;      (foo x p)
    ;;      (define x #f)
    ;;      p)))          ; Syntax violation: Definition of identifier that may
have
    ;;                    ; already affected meaning of undeferred portions of
body: x

    ;;(let-syntax ((def0 (syntax-rules ()
    ;;                     ((_ x) (define x 0)))))
    ;;  (let ()
    ;;    (def0 z)
    ;;    (define def0 '(def 0))
    ;;    (list z def0))) ; Syntax violation: Definition of identifier that may
have
    ;;                    ; already affected meaning of undeferred portions of
body: def0

    ;;(let ()
    ;;  (define define 17)
    ;;  define)        ; Syntax violation: Definition of identifier that may have
    ;;                 ; already affected meaning of undeferred portions of body:
define

    ;; (define-syntax foo (syntax-rules () ((_ x) (define x 1))))
    ;;   (let ((b 2))
    ;;     (foo a)
    ;;     (define (foo x) 2)
    ;;     (foo b)
    ;;     (values a b)) ; Syntax violation: Definition of identifier that may
have
    ;;                   ; already affected meaning of undeferred portions of
body: foo

    ;; (define-syntax foo (syntax-rules () ((_ x) (define x 1))))
    ;;   (let ()
    ;;     (foo a)
    ;;     (define-syntax foo (syntax-rules () ((_ x) (define x 2))))
    ;;     (foo b)
    ;;     (values a b))  ; Syntax violation: Definition of identifier that may
have
    ;;                    ; already affected meaning of undeferred portions of
body: foo

    ;; This should still be valid.

    (let ()
      (define-syntax foo
        (syntax-rules ()
          ((_ def0) (def0 define 17))))
      (foo define)
      0)

    ;; Distinguishing literals from non-literal data:

    (let ()
      (define-syntax list-macro
        (syntax-rules ()
          ((_ x ...) (list x ...))))
      ;; This must give violation:
      ;;(define ... 1)  ; Syntax violation: Definition of identifier that may
have already
      ;;                ; affected meaning of undeferred portions of body: ...
      ;; But this must not:
      (define list cons)
      (list-macro 1 2))   ;==> (1 . 2)

    ;;(let ()
    ;;  (define-syntax macro
    ;;    (let ((x `(1 ,2)))
    ;;      (lambda (form) x)))
    ;;  (define unquote 2)
    ;;  (macro))    ; Syntax violation: Definition of identifier that may have
already
    ;;              ; affected meaning of undeferred portions of body: unquote

    ;; Have to make sure that previous does give violation but this does not.
    (let ()
      (define-syntax macro
        (let ((x `(+ ,2)))
          (lambda (form) (cadr x))))
      (define + 2)
      (macro))    ;==> 2