[plt-scheme] syntax-object comparison

From: Matthew Flatt (mflatt at cs.utah.edu)
Date: Fri May 7 12:19:39 EDT 2004

> 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




Posted on the users mailing list.