Whoa, very nice! IIUC, you could get rid of syntax-local-eval because you have a sub-macro, so the overall macro puts the content of id-rename inside a sub-macro that is then evaluated. This is also why id is correctly "bound" inside (begin body ...) : after the first expansion, it is not really body ..., but the full expression containing id. It is definitely better.
Also, the first let () is not really needed I guess. Thank you very much. Laurent On Mon, Apr 18, 2011 at 20:42, Jon Rafkind <[email protected]> wrote: > Here is an alternative implementation that makes the example you showed at > the very bottom of your emails work. I don't know if its "better" but using > `syntax-local-eval' looks somewhat dangerous to me. > > This is mostly straight-forward except that to get the right lexical scope > for `get-x1' we need to do a little hack (by assuming the argument list has > at least one thing in it). Of course the original macro could enforce such a > property as well. > > #lang racket > > > (define-syntax (define-syntax-rule/id stx) > (syntax-case stx () > [(_ (name arg ...) > [id id-rename] > body ...) > (let () > #'(define-syntax (name stx) > (syntax-case stx () > [(_ arg ...) > ;; we want the defined procedure to have the same lexical scope > as > ;; the arguments given to the syntax-rule > ;; we can't use #'(arg ...) as the thing to get the lexical > scope > ;; because #' will create a new syntax object using the lexical > ;; scope of the code right here. so instead we take out the > first > ;; object from the argument list which should have the right > scope. > (with-syntax ([id (datum->syntax (car (syntax->list #'(arg > ...))) > (string->symbol > (let ([arg (syntax-e #'arg)] > ...) > id-rename)) > (car (syntax->list #'(arg > ...))))]) > #'(begin body ...))])) > )])) > > (define-syntax-rule/id (make-getter xid) > [id2 (format "get-~a" xid)] > (define (id2) xid)) > > (define x1 5) > (make-getter x1) > (get-x1) > > > > On 04/18/2011 12:03 PM, Laurent wrote: > > Found! > > After having read more carefully Eli's very good post ( > http://blog.racket-lang.org/2011/04/writing-syntax-case-macros.html), it > became clearer that the problem was that the context of the created > identifier was wrong. > Deconstructing and reconstructing the id syntax object did the trick: > > (define-syntax (define-syntax-rule/id stx) > (syntax-case stx () > [(_ [id id-gen] body) > (with-syntax ([id-def (to-syntax > (syntax-e (syntax-local-eval #'id-gen)) > #:stx stx)]) > #'(splicing-let-syntax ([tmp-form (syntax-rules () > [(_ id) (begin (displayln 'body) > body)])]) > (tmp-form id-def)) > )] > )) > > > Now if anyone knows a better way to implement this or can point out > problems with this implementation, I'd be glad to know about it. > > Thanks for listening :) > Laurent > > > On Mon, Apr 18, 2011 at 18:21, Laurent <[email protected]> wrote: > >> Dear Racket list, >> >> Once again, I need a little help on a macro definition. >> >> I want to define the following (simplified[1]) macro: >> (define-syntax-rule/id [*id id-gen*] *body*) >> >> where id is replaced with the result of id-gen inside body. >> For example: >> (define-syntax-rule/id >> [x #'foo] >> (begin (define x 5) >> (displayln x))) >> >> is supposed to bind foo to 5 in the top-level at run-time. >> (You can replace #'foo by some complex identifier-making expression using >> format-id.) >> Here is what I have right now, after much trial&error: >> >> #lang racket >> >> (require (for-syntax unstable/syntax) >> (for-syntax errortrace/errortrace-key) >> racket/splicing >> ) >> >> (provide (all-defined-out)) >> >> ;; Like define-syntax-rule, >> ;; but id is replaced with the result of id-gen in body. >> ;; id-gen is eval'ed at macro-time. >> (define-syntax (define-syntax-rule/id stx) >> (syntax-case stx () >> [(_ [id id-gen] body) >> (with-syntax ([id-def (syntax-local-eval #'id-gen)]) >> #'(splicing-let-syntax ([tmp-form (syntax-rules () >> [(_ id) (begin (displayln 'body) >> body)])]) >> (tmp-form id-def)) >> )] >> )) >> >> ;;; TESTS >> >> (define-syntax-rule/id >> [x #'foo] >> (begin (define x 5) >> (displayln x) >> (displayln 'x) >> )) >> >> >> It works (foo is bound to 5), except that foo is unknown (undefined >> identifier) after the (begin ...). >> I suspect this is because of syntax-local-eval, but I don't know what to >> use instead. >> >> There is another intriguing thing: >> if just after (define x 5) we add (provide x), and in another file we >> require the first file, then foo is actually defined and can be used >> normally! >> Why is that and why does this not work when there is no (provide x) ? >> [note that there is a (provide (all-defined out)).] >> >> Can someone give me a hint as to what is going on? >> >> I also suspect that using splicing-let-syntax is not the way to go, but >> again I don't know what to use otherwise, that would let me replace id with >> id-def. >> >> Thank you very much, >> Laurent >> >> >> [1] To explain the name: once finished, this macro will be supposed to >> behave like an augmented version of define-syntax-rule but with explicit >> hygiene breaking: >> >> (define-syntax-rule/id (make-getter id) >> [id2 (format-id #'here "get-~a" id)] >> (define (id2) id)) >> >> which, when called on (make-getter foo) would create the get-foo function. >> > > > _________________________________________________ > For list-related administrative tasks: > http://lists.racket-lang.org/listinfo/users > > > > _________________________________________________ > For list-related administrative tasks: > http://lists.racket-lang.org/listinfo/users >
_________________________________________________ For list-related administrative tasks: http://lists.racket-lang.org/listinfo/users

