Summary

compare doesn't compare if name is already bound

Metadata

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))

Changes and comments

[2022-06-07 07:04:57 UTC] sjamaan changed status from new to closed

[2022-06-07 07:04:57 UTC] sjamaan set resolution to invalid

[2022-06-07 07:04:57 UTC] sjamaan wrote:

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 in `frob-bad`, or use `strip-syntax` like you're doing in `frob-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.