Re: [racket-users] Macro-generating macros
> On Sep 4, 2015, at 4:26 AM, Konrad Hinsenwrote: > > Brian Mastenbrook writes: > >> It's a capture problem. In the first case, you're just binding the >> name "send" locally and all is well. In the second case, you're >> trying to introduce a binding for "send" that you didn't get from >> the input form. > > Ahhh that one has bitten me before, but I had forgotten about it. > Thanks for the reminder! > >> You're also getting a confusing error because "send" is already >> bound; try using a name that's not already defined and you should >> get an unbound identifier. > > I used a bound symbol intentionally to see if I can shadow an existing > syntax transformer binding. Ok, if you *really* want to shadow an existing binding, you can use datum->syntax, but using a syntax parameter is much better: (define-syntax (def stx) (syntax-parse stx [(_ (fn-name:id arg:id ...) body ... ) #:with send-id (datum->syntax #'fn-name 'send) #'(define (fn-name arg ...) (let-syntax ([send-id (λ (stx) (syntax-parse stx [(send-id obj:expr method:id x:expr (... ...)) #'(method obj x (... ...))]))]) body ...))])) >> Alternatively, you can use a syntax parameter, which is probably >> the ideal solution here. > > At least it's one that works. It feels like cheating to use dynamic > scoping to get around a problem with lexical scoping, but knowing when > to cheat is a fundamental competence when dealing with any bureaucracy ;-) Um, the reason a syntax parameter is better is that it *does* follow the lexical scoping rules, where the unhygienic version does weird things you wouldn't expect. Using datum->syntax is cheating a lot more, and syntax parameters deal with problems like this in a much better way. P.S. Have you read Fear of Macros? If you haven't, I highly recommend it because it's awesome. > Thanks again, > Konrad. -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] Macro-generating macros
Racket's syntax-expander deliberately goes out of its way to break exactly this example. ("hygiene") The issue/bug/ambiguity it is protecting you from is: (let ((send (lambda args (length args)) )) (def (foo3 x y) (send x + y) )) (foo3 2 3) ;; In lisps with poor grooming, 5. In racket, 3. 3 is not what you wanted this time, but it is the better default behavior overall. There are many ways to get exactly the desired syntactic behavior; syntax parameters work, as does datum->syntax. If you're willing to bend a little, a more racket-y solution, it seems to me, is to force the user of the syntax to give you a name, like: (define-syntax-rule (with-SVO-as name body ...) (let-syntax ((name (syntax-rules [(_ s v o ...) (v s o ...)] ))) body ...) Which can be used like: (define (foo4 x y) (with-SVO-as send (send x + y))) Or like: (define-syntax send (with-SVO-as n n)) (define (foo5 x y) (send x + y)) Or like: (define (foo6 x y) (define-syntax send (with-SVO-as n n)) (send x + y)) That approach doesn't work so well for things like: (with-slots (x y z) (person-x person-y person-z) the-person (sqrt (* x x) (* y y) (* z z))) That is, when there are lots of names to be bound, and they're pretty much always the same, then the repetition/renaming at each use-site gets quite tiresome; that is the problem that modules solve. -Will On Thu, Sep 3, 2015 at 9:59 AM, Brian Mastenbrookwrote: > On Sep 3, 2015, at 11:44, Konrad Hinsen > wrote: > > > Hi everyone, > > > > Here's another plea for help from the macro experts. I am trying to > > write a macro whose expansion contains another macro, more precisely a > > let-syntax form. My full example is attached below. In the first part, > > I use a let-syntax directly. In the second part, I use a macro that > > generates exactly the form that I wrote by hand in the first part - > > but then the let-syntax seems to be ignored. > > > > The macro stepper isn't of much help here. It shows the expansion > > of (defn (foo2 ...)) into essentially what I wrote by hand for foo1, > > and then declares the expansion finished. > > > > Can anyone tell me (1) why this doesn't work and (2) how to fix it? > > It's a capture problem. In the first case, you're just binding the name > "send" locally and all is well. In the second case, you're trying to > introduce a binding for "send" that you didn't get from the input form. > You're also getting a confusing error because "send" is already bound; try > using a name that's not already defined and you should get an unbound > identifier. > > You can fix this in one of two ways. Your `def' macro could take the name > of the `send' macro it binds as a parameter, which gets a little ugly. > Alternatively, you can use a syntax parameter, which is probably the ideal > solution here. > > (require (for-syntax syntax/parse)) > (require racket/stxparam) > > (define-syntax-parameter send (lambda (stx) (raise-syntax-error 'send > "send used out of context"))) > > (define-syntax (def stx) > (syntax-parse stx >[(_ (fn-name:id arg:id ...) body ... ) > #'(define (fn-name arg ...) > (syntax-parameterize ([send (λ (stx) > (syntax-parse stx > [(send obj:expr method:id x:expr > (... ...)) > #'(method obj x (... ...))]))]) > body ...))])) > > (def (foo2 x y) > (send x + y)) > > (foo2 2 3) > > > -- > Brian Mastenbrook > br...@mastenbrook.net > http://brian.mastenbrook.net/ > > -- > You received this message because you are subscribed to the Google Groups > "Racket Users" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to racket-users+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/d/optout. > -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] Macro-generating macros
Alexander D. Knauth writes: > > At least it's one that works. It feels like cheating to use dynamic > > scoping to get around a problem with lexical scoping, but knowing when > > to cheat is a fundamental competence when dealing with any bureaucracy ;-) > > Um, the reason a syntax parameter is better is that it *does* > follow the lexical scoping rules, where the unhygienic version does > weird things you wouldn't expect. Using datum->syntax is cheating a > lot more, and syntax parameters deal with problems like this in a > much better way. I agree that datum->syntax is cheating a lot more, no question. Still, I just used it, and I don't feel bad about it because it makes my code a lot more readable. I had gotten to the point of having a macro introduce generated identifiers as syntax parameters for use by another macro generated by the first macro as well. Actually, I felt exactly like when I have to fight a type system: I know my solution is OK, but the compiler cannot prove it and therefore rejects it. In those cases I feel entitled to cheat as much as necessary. > P.S. Have you read Fear of Macros? If you haven't, I highly > recommend it because it's awesome. It is. I had read it a year ago, and now re-read it. I'll probably have to read it again in the future, but it *is* awesome :-) Konrad. -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] Macro-generating macros
Brian Mastenbrook writes: > It's a capture problem. In the first case, you're just binding the > name "send" locally and all is well. In the second case, you're > trying to introduce a binding for "send" that you didn't get from > the input form. Ahhh that one has bitten me before, but I had forgotten about it. Thanks for the reminder! > You're also getting a confusing error because "send" is already > bound; try using a name that's not already defined and you should > get an unbound identifier. I used a bound symbol intentionally to see if I can shadow an existing syntax transformer binding. > Alternatively, you can use a syntax parameter, which is probably > the ideal solution here. At least it's one that works. It feels like cheating to use dynamic scoping to get around a problem with lexical scoping, but knowing when to cheat is a fundamental competence when dealing with any bureaucracy ;-) Thanks again, Konrad. -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
[racket-users] Macro-generating macros
Hi everyone, Here's another plea for help from the macro experts. I am trying to write a macro whose expansion contains another macro, more precisely a let-syntax form. My full example is attached below. In the first part, I use a let-syntax directly. In the second part, I use a macro that generates exactly the form that I wrote by hand in the first part - but then the let-syntax seems to be ignored. The macro stepper isn't of much help here. It shows the expansion of (defn (foo2 ...)) into essentially what I wrote by hand for foo1, and then declares the expansion finished. Can anyone tell me (1) why this doesn't work and (2) how to fix it? Thanks in advance, Konrad. == #lang racket (require syntax/parse) (require (for-syntax syntax/parse)) ; ; this works fine ; (define (foo1 x y) (let-syntax ([send (λ (stx) (syntax-parse stx ((send obj:expr method:id x:expr ...) #'(method obj x ...]) (send x + y))) (foo1 2 3) ; ; this doesn't ; (define-syntax (def stx) (syntax-parse stx [(_ (fn-name:id arg:id ...) body ... ) #'(define (fn-name arg ...) (let-syntax ([send (λ (stx) (syntax-parse stx [(send obj:expr method:id x:expr (... ...)) #'(method obj x (... ...))]))]) body ...))])) (def (foo2 x y) (send x + y)) (foo2 2 3) ;; send: target is not an object ;; ; target: 2 ;; ; method name: + ;; ; -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [racket-users] Macro-generating macros
On Sep 3, 2015, at 11:44, Konrad Hinsenwrote: > Hi everyone, > > Here's another plea for help from the macro experts. I am trying to > write a macro whose expansion contains another macro, more precisely a > let-syntax form. My full example is attached below. In the first part, > I use a let-syntax directly. In the second part, I use a macro that > generates exactly the form that I wrote by hand in the first part - > but then the let-syntax seems to be ignored. > > The macro stepper isn't of much help here. It shows the expansion > of (defn (foo2 ...)) into essentially what I wrote by hand for foo1, > and then declares the expansion finished. > > Can anyone tell me (1) why this doesn't work and (2) how to fix it? It's a capture problem. In the first case, you're just binding the name "send" locally and all is well. In the second case, you're trying to introduce a binding for "send" that you didn't get from the input form. You're also getting a confusing error because "send" is already bound; try using a name that's not already defined and you should get an unbound identifier. You can fix this in one of two ways. Your `def' macro could take the name of the `send' macro it binds as a parameter, which gets a little ugly. Alternatively, you can use a syntax parameter, which is probably the ideal solution here. (require (for-syntax syntax/parse)) (require racket/stxparam) (define-syntax-parameter send (lambda (stx) (raise-syntax-error 'send "send used out of context"))) (define-syntax (def stx) (syntax-parse stx [(_ (fn-name:id arg:id ...) body ... ) #'(define (fn-name arg ...) (syntax-parameterize ([send (λ (stx) (syntax-parse stx [(send obj:expr method:id x:expr (... ...)) #'(method obj x (... ...))]))]) body ...))])) (def (foo2 x y) (send x + y)) (foo2 2 3) -- Brian Mastenbrook br...@mastenbrook.net http://brian.mastenbrook.net/ -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.