Yesterday, Brian Mastenbrook wrote: > > I find it interesting that you used a separate syntax parameter > instead of just making `outer' the syntax parameter. I think that > the semantics are the same with either strategy, but for some reason > the latter seems more obvious to me - perhaps because it's closest > to the non-syntax-parameterized version of this macro, and avoids > the need for `syntax-parameter-value' entirely.
In general uses of `syntax-parameter-value' are rare. Another point is that the use of splicing makes the explanation more complicated than it could be -- and since `def' allows only function definitions, there's no real need for it. > Can you elaborate on why you used `syntax-e' instead of > `syntax->datum'? I would ordinarily expect something like (outer > (add1 x)) to use the outer version of `x'. I also think that this makes it better. Here's a version that has the above and this: (define-syntax-parameter outer (λ (stx) (raise-syntax-error 'outer "can't be used here"))) (define-syntax (def stx) (syntax-case stx () [(_ (name args ...) body ...) #`(define name (syntax-parameterize ([outer (λ (stx*) (syntax-case stx* () [(_ id) (datum->syntax #'#,stx (syntax->datum #'id) stx*)]))]) (λ (args ...) body ...)))])) > Is there a way to make (outer (outer x)) do the right thing while still > using syntax parameters? That's an obvious bait, right? (define-syntax (def stx) (syntax-case stx () [(_ (name args ...) body ...) #`(define name (let-syntax ([#,(datum->syntax stx 'outer stx) (λ (stx*) (syntax-case stx* () [(_ id) (datum->syntax #'#,stx (syntax->datum #'id) stx*)]))]) (λ (args ...) body ...)))])) > Do you consider this behavior to be surprising? Would you expect as > the author of `m' that your macro affects the behavior of `outer'? > > (define-syntax m > (syntax-rules () > ((_ val) > ;; Helper function > (let () > (def (h i) (* i val)) > (h 2))))) > > (def (g x) > (def (h x) > (m (outer x))) > (h 3)) > > -> "expand: unbound identifier in module in: x" That's not more surprising than using plain parameters: (define p (make-parameter #f)) (define (m thunk) (parameterize ([p 2]) (thunk))) (define (g) (parameterize ([p 1]) (m (λ () (p))))) (g) ; -> 2 The question is whether `m' should affect the value of `p' while running the thunk -- in this example, it's kind of obvious that it *wants* to do that, so there's no real surprise (provided that it's documented to do this change). If it doesn't want to do that but it still needs to change `p' for whatever reason, then you'd write something like: (define (m thunk) (define old-p (p)) (parameterize ([p 2]) (parameterize ([p old-p]) (thunk)))) This looks silly, but "whatever reason" could be some code before+after running the thunk, so another way to do this would be: (define (m thunk) (parameterize ([p 2]) (before)) (thunk) (parameterize ([p 2]) (after))) And the same can be done with syntax parameters. An hour and a half ago, Danny Yoo wrote: > > Ok, the following code is an extension to the first version that > should resolve the problem. That's a cute trick, but you can't really win this battle, since there would be cases where you'll *want* the previous behavior. For example, this: (define-syntax-rule (outer-x) (outer x)) (def (f x) (def (g x) (outer-x)) (g 1)) worked with the previous version, but not with this one. (And also not with the unhygienic variation above.) -- ((lambda (x) (x x)) (lambda (x) (x x))) Eli Barzilay: http://barzilay.org/ Maze is Life! ____________________ Racket Users list: http://lists.racket-lang.org/users