Summary
compare doesn't compare if name is already bound
Metadata
- Id: b664815127562c2e29f84f40e7693827d7546809
- Trac id: 1804
- Type: defect
- Reporter: Idiomdrottning
- Owner:
- Cc:
- Status: closed
- Component: expander
- Estimated difficulty: medium
- Resolution: invalid
- Priority: major
- Milestone: someday
- Version: 5.2.0
- Changetime: 2022-06-07 07:04:57 UTC
- Created: 2022-06-05 14:37:29 UTC
- Keywords:
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.