I would like to register a slight disagreement with the response to formal
comment 61: "Expansion process violates lexical scoping".
- Lexical scoping is, in my opinion, too basic a property of the
language to permit leaving its enforcement up to the user.
I believe it would be better if the syntactic check were mandatory and
not optional as stated in the response.
To support this, I would like to point out that several of the
commented out examples below give lexical-scope-violating answers on
MzScheme and/or Chez. The problems with these fragments are not
always immediately obvious even to experienced people, and it may
be asking too much to expect users to anticipate them and do the required
alpha-renaming (for example) to avoid them. That should be the job of the
expander, which should be reliable.
- An algorithm that avoids these violations exists. It is trivial to
implement. It was also, in my implementation, easier to implement
than the r5.91rs algorithm.
- It is not expensive. I found the slowdown, if any, over the r5.91rs
algorithm, to be imperceptible.
- The algorithm is single-pass left-to-right.
The algorithm is implemented in the newer version of the implementation at
http://www.het.brown.edu/people/andre/macros/
and may be summarized as follows:
It is a syntax violation if an identifier whose meaning is needed
during the left-to-right expansion of definitions is subsequently
redefined by a definition in the same body. To detect this error, the
expander records each identifier reference occurring during
expansion of the body.
Before an identifier is bound, its current binding is compared
against bindings already referenced for the same (in the sense of
bound-identifier=?) identifier during the expansion of the definitions.
If a match is found, the binding may have already affected the
expansion of the body, and a syntax violation is therefore thrown.
This algorithm correctly throws an error for all the cases below where the
current draft algorithm would allow lexical violations. Several of the
commented out examples below give incorrect answers on MzScheme and/or Chez.
;; This must give an error:
;; (let ()
;; (define-syntax foo (lambda (e) (+ 1 2)))
;; (define + 2)
;; (foo)) ; Syntax violation: Redefinition of identifier + that
;; has already been referenced during expansion of body
;; This gives no error:
(let ()
(define-syntax foo (lambda (e) (let ((+ -)) (+ 1 2))))
(define + 2)
(foo)) ;==> -1
;; This must give an error:
;; (script
;; (import r6rs)
;; (bar x)
;; (define-syntax bar
;; (syntax-rules ()
;; ((bar x) (define x 1))))
;; x) ; Syntax violation: Redefinition of identifier bar that has
;; already been referenced during expansion of body
;;(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: Redefinition of identifier x that has
;; already been referenced during expansion of body
;; Still, the following is valid.
(let ((x #f))
(let-syntax ((foo (syntax-rules (x)
((_ x y) (define y 'outer))
((_ _ y) (define y 'inner)))))
(let ()
(define x #f)
(foo x p)
p))) ;==> inner
;;(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: Redefinition of identifier x that has
;; already been referenced during expansion of body
;;(let-syntax ([def0 (syntax-rules ()
;; [(_ x) (define x 0)])])
;; (let ()
;; (def0 z)
;; (define def0 '(def 0))
;; (list z def0))) ; Syntax violation: Redefinition of identifier def0 that has
;; already been referenced during expansion of body
;;(let ()
;; (define define 17)
;; define) ; Syntax violation: Redefinition of identifier define that has
;; already been referenced during expansion of body
;; (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: Redefinition of identifier foo that has
;; ; already been referenced during expansion of body
;; (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: Redefinition of identifier foo that has
;; ; already been referenced during expansion of body
;; This should still be valid.
(let ()
(define-syntax foo
(syntax-rules ()
((_ def0) (def0 define 17))))
(foo define)
0)
Andre
Received on Sun Dec 17 2006 - 13:42:09 UTC