[racket] How does free-identifier=? and bound-identifier=? works?

From: Veer (diggerrrrr at gmail.com)
Date: Mon Apr 11 04:38:57 EDT 2011

Thank you Ryan , for clearing my absolute misconception about
free-identifier=? and bound-identifier=? .

I think hopefully I now have better understanding of free-identifier=?
and bound-identifier=? .

Initially it took some time to understand purpose behind bound-identifier=? ,
but I think I managed to get its use from your use case (hopefully).

(define-syntax (new-binding-form stx)
  (syntax-case stx ()
    [(_ ((x1 e1) (x2 e2) ) body)
     (if (and (identifier? #'e2)
              (bound-identifier=? #'x1 #'e2))
       #'(let ([x1 e1])
           (let ([x2 x1])

(new-binding-form ((x 2) (y x)) (+ x y))
(new-binding-form ((x 2) (y 3)) (+ x y))

For free-identifier=? , I think this is what you meant by
recognising else keyword right?

(define-syntax (cond2 stx)
  (syntax-case stx (else1)
    [(_ (else1 exp)) #'exp]
    [(_ (pred exp)) #'(when pred exp)]
    [(_ (pred1 exp1) (pred2 exp2) ...)
     (if (and (identifier? #'pred1)
              (free-identifier=? #'pred1 #'else1))
          #'(error 'cond2 "else should be last clause...")
          #'(if pred1
                (cond2 (pred2 exp2) ...)))]))

;;this is returns 7
  (#f 4)
  (else1 7))

;;this cause error
  (else1 3)
  (else1 4))

;;returns 2
(let ((else1 1))
    (else1 2)
    (else1 3)))

Thanks again for explaining in such detail and simplicity.


On Sun, Apr 10, 2011 at 4:59 PM, Ryan Culpepper <ryanc at ccs.neu.edu> wrote:
> On 04/10/2011 12:31 AM, Veer wrote:
>> Hello,
>> I am unable to understand how free-identifier=? and bound-identifier=?
>> works?
>> For example suppose I have a code :
>>    (lambda (x y) (let ([x 2]) x))
>> then how do I determine if last x in the body of let is not bound by first
>> parameter to lambda? , using either free-identifier=? or
>> bound-identifier=? .
> You can only get answers to questions like this *after* expanding the
> program. You might have a notion of the scoping rules of lambda and let, but
> free-identifier=? et al don't; they can only tell you what the macro
> expander has discovered about the program's binding structure.
> Before any expansion, the macro expander hasn't made any discoveries, so all
> xs look alike.
> After expansion, you get something that looks like this:
>  (lambda (x y) (let-values ([(x) '2]) x)
> so you'll have to rewrite your pattern, but now you can ask questions using
> free-identifier=?. (IIRC, free-identifier=? and bound-identifier=? are
> equivalent on fully-expanded programs.)
> During macro expansion, free-identifier=? and bound-identifier=? compare
> identifiers based on the discoveries available at that point in time.
> (free-identifier=? x y) means if these two identifiers were turned into
> references right now, would they refer to the same binding. It's how cond,
> for example, recognizes the else keyword: does the identifier the macro gets
> refer to the same binding as a known good reference to else.
> (bound-identifier=? x y) means if one of the identifiers were turned into a
> binding occurrence and the other were turned into a reference in its scope,
> eg (lambda (x) y), would the second refer to the first. This is usually only
> used when you're implementing a new binding form to check for duplicates,
> etc, or for really odd macros that act kind of like binding forms but don't
> use Racket's core binding forms to do it.
> Ryan

Posted on the users mailing list.