Opened 2 years ago
Closed 2 years ago
#1804 closed defect (invalid)
compare doesn't compare if name is already bound
Reported by: | Idiomdrottning | Owned by: | |
---|---|---|---|
Priority: | major | Milestone: | someday |
Component: | expander | Version: | 5.2.0 |
Keywords: | Cc: | ||
Estimated difficulty: | medium |
Description
(define-syntax frob-bad (ir-macro-transformer (lambda (exp inject compare) (let ((body (cdr exp))) `',(let desc ((friends '()) (body body)) (cond ((null? body) friends) ((pair? body) (append (desc friends (car body)) (desc friends (cdr body)))) ((any (cut compare body <>) '(x y z rest args)) (cons (strip-syntax body) friends)) (else '()))))))) (equal? ((lambda (x) (frob-bad (reverse x))) 'foo) ; unexpected behavior. Since x is bound in the scope. ((lambda (p) (frob-bad (reverse x))) 'foo) ; expected behavior. Since x is not bound in the scope. ) (define-syntax frob-good (ir-macro-transformer (lambda (exp inject compare) (let ((body (cdr exp))) `',(let desc ((friends '()) (body body)) (cond ((null? body) friends) ((pair? body) (append (desc friends (car body)) (desc friends (cdr body)))) ((memq (strip-syntax body) '(x y z rest args)) (cons (strip-syntax body) friends)) (else '()))))))) (equal? ((lambda (x) (frob-good (reverse x))) 'foo) ; working workaround by eq? after strip-syntax instead of compare ((lambda (p) (frob-good (reverse x))) 'foo))
Note: See
TracTickets for help on using
tickets.
This works as expected - you're trying to compare unhygienically against
x
, so you should either use(inject '(x y z rest args))
for the comparison infrob-bad
, or usestrip-syntax
like you're doing infrob-good
.The comparison procedure works analogously to explicit renaming macros, but using implicit renaming. So when you compare against a value, it takes the value you pass it and implicitly renames it before comparing, just like it would've done on the output.