[plt-scheme] syntax-object comparison
> I'm having trouble figuring out all the differences between the
> syntax-object comparison procedures. Can someone please give examples
> where the following procedures will give different answers?
>
> bound-identifier=?
> free-identifier=?
> module-identifier=?
> module-transformer-identifier=?
> module-or-top-identifier=? ;from (lib "stx.ss" "syntax")
> (lambda (s1 s2) (eq? (syntax-e s1) (syntax-e s2)))
Here's a start.
Matthew
----------------------------------------
(define-syntax define-compare
(syntax-rules ()
[(_ id =?) (define-syntax (id stx)
(syntax-case stx ()
[(_ a b) (datum->syntax-object stx (=? #'a #'b))]))]))
;; Beware: bound=? looks like a function, but it's
;; a macro that produces #t/#f based on the synactic
;; identifiers that follow.
(define-compare bound=? bound-identifier=?)
(define-compare free=? free-identifier=?)
(define-compare module=? module-identifier=?)
(define-compare symbol=? (lambda (s1 s2) (eq? (syntax-e s1) (syntax-e s2))))
;; Until macros get involved, everything's obvious:
(bound=? x x) ; => #t
(bound=? x y) ; => #f
(let ([x 10])
(bound=? x x)) ; => #t
(free=? x x) ; => #t
(free=? x y) ; => #f
(let ([x 10])
(free=? x x)) ; => #t
(module=? x x) ; => #t
(module=? x y) ; => #f
(let ([x 10])
(module=? x x)) ; => #t
(symbol=? x x) ; => #t
(symbol=? x y) ; => #f
(let ([x 10])
(symbol=? x x)) ; => #t
;; Simple macro: introduce an "x". This exposes
;; the difference between bound, free, and sym =.
(let-syntax ([bound=x? (syntax-rules ()
[(_ id) (bound=? id x)])]
[free=x? (syntax-rules ()
[(_ id) (free=? id x)])]
[module=x? (syntax-rules ()
[(_ id) (module=? id x)])]
[symbol=x? (syntax-rules ()
[(_ id) (symbol=? id x)])])
(list
(bound=x? x) ; => #f
(let ([x 10])
(bound=x? x)) ; => #f
(free=x? x) ; => #t
(let ([x 10])
(free=x? x)) ; => #f
(module=x? x) ; => #t
(let ([x 10])
(module=x? x)) ; => #f
(symbol=x? x) ; => #t
(let ([x 10])
(symbol=x? x)) ; => #t
))
;; To see the difference between free and module,
;; import with a rename.
(require mzscheme)
(require (rename mzscheme cons2 cons))
(free=? cons cons2) ; => #f
(module=? cons cons2) ; => #t
;; Re-define `cons' at the top level, so
;; that it no longer refers directly to
;; the MzScheme import:
(define cons (lambda (x y) (cons2 x y)))
(free=? cons cons2) ; => #f
(module=? cons cons2) ; => #f
;; Furthemore, `cons' is no longer `module=?' to `cons'
;; from a context where it means the MzScheme export.
;; Hence module-or-top-identifier=?...
(require-for-syntax (lib "stx.ss" "syntax"))
(define-compare module-or-top=? module-or-top-identifier=?)
(module m mzscheme
(provide compare-to-cons)
(define-syntax compare-to-cons
(syntax-rules ()
[(_ =? id) (=? id cons)])))
(require m)
(compare-to-cons free=? cons) ; => #f
(compare-to-cons symbol=? cons) ; => #t
(compare-to-cons module=? cons) ; => #f
(compare-to-cons module=? cons2) ; => #t
(compare-to-cons module-or-top=? cons) ; => #t
;; The renaming `require' and the definition of `cons'
;; did not affect the compile-time environment, but
;; `require-for-syntax' does
(define-compare module-trans=? module-transformer-identifier=?)
(require-for-syntax (rename mzscheme cons3 cons))
(module-trans=? cons cons) ; => #t
(module-trans=? cons cons2) ; => #f
(module-trans=? cons cons3) ; => #t
(compare-to-cons module-trans=? cons) ; => #t
(compare-to-cons module-trans=? cons2) ; => #f
(compare-to-cons module-trans=? cons3) ; => #t