[racket] macro masters needed! bound-identifier=? help for Racket / Rust

From: John Clements (clements at brinckerhoff.org)
Date: Tue Jul 23 14:24:10 EDT 2013

Dag Nabbit! Just when I thought I understood everything. I'm struggling to implement the "Macros That Work Together" system--or part of it, anyhow--in Rust, and bound-identifier=? (in Racket) doesn't work quite the way I thought it did.

#lang racket

(define expanded
  (expand
   #'(let ([x 19])
       (define-syntax getx
         (syntax-rules () [(_) x]))
       (getx))))

(printf "expanded: ~v\n" (syntax->datum expanded))

(syntax-case expanded ()
  [(let-vals (((x-binding) d))
             (c1 c2 x-use)) 
   (begin
     (printf "x-binding: ~v\n" #'x-binding)
     (printf "x-use: ~v\n" #'x-use)
     ;; yep, this is good:
     (printf "free-id=? ~v\n"(free-identifier=? #'x-binding #'x-use))
     ;; wait! no! this should be false.... urrr:
     (printf "bound-id=? ~v\n" (bound-identifier=? #'x-binding #'x-use)))])

==produces==>

Welcome to DrRacket, version 5.3.5.900 [3m].
Language: racket; memory limit: 512 MB.
expanded: '(let-values (((x) '19)) (let-values () x))
x-binding: .#<syntax:5:12 x>
x-use: .#<syntax:8:7 x>
free-id=? #t
bound-id=? #t
> 

In particular, this result--that the binding instance of 'x' and the macro-introduced use of 'x' are *bound*-identifier=?--surprises me.

To take a step back, my low-level understanding of free-identifier=? is "resolves to the same name in the Macros That Work Together (MTWT) sense"... and it makes sense to me that these both resolve to the same name.  In particular, the use of "let" generates a rename that applies to all uses of 'x' that have the same set of marks (none) as the binder, and that includes the use of 'x' in the RHS of the macro definition. All good.

But now, consider bound-identifier=?. My understanding was that bound-identifier=? corresponds to "resolves to the same name *and* has the same set of marks", such that a rename of one of them would capture the other one, too. And in this case, I would *not* expect the x binding and the x introduced by the macro to have the same set of marks.  Here's why: the 'x' introduced by the use of (getx) should have received the mark applied on exit from the macro, but not the mark applied on entrance to the macro.  This means that these marks would not cancel, and that the use of 'x' in the body would have a different set of marks from the 'x' in the body.

Can anyone help me diagnose my misunderstanding?

Many, many thanks in advance,

John



Posted on the users mailing list.