Yes, that works, thank you. I didn't know that one could use something other than the usual `stx` inside `format-id`.
On Mon, Oct 27, 2014 at 1:24 PM, Matthew Flatt <mfl...@cs.utah.edu> wrote: > We sometimes call this the "non-hygienic macros compose poorly" > problem. > > The two-subform case of `definer` uses the overall form, `stx`, to > provide a content for the introduced `arg-id` binding. So, when you use > the two-subform variant directly in some context, then you can see the > `arg-id` binding in that same context. > > When you use the one-subform `definer`, it expands to a two-subform > `definer`, but that new `definer` form is macro-introduced. > Consequently, further expansion also marks `arg-id` as > macro-introduced, and so `arg-id` becomes inaccessible from the context > that used the one-subform `definer`. > > > In this case, using the given `id` as the lexical context for the > synthesized name (instead of the overall `definer` form) is almost > certainly what you want: > > (format-id #'id "~a-~a" #'arg #'id) > > That makes `zam-baz-id` visible in the same contexts as `baz-id`. It's > still a non-hygienic macro in some sense, but it's an ok kind, because > the context for the introduced binding comes from a sensible part of > the macro use. > > > At Mon, 27 Oct 2014 13:10:39 -0700, Matthew Butterick wrote: > > I'm unclear why I'm getting an unbound-identifier error in this macro. > I've > > written other self-referencing macros in the past that have worked, so > I'm > > unclear why this one doesn't. > > > > What I expect is that when `definer` is called with one argument, the > first > > branch of `syntax-case` will stick on a default argument and call > `definer` > > again. Which it does, except that in that case, it only binds the name > 'id' > > rather than both 'id' and 'arg-id'. > > > > > > #lang racket > > (require (for-syntax racket/syntax) rackunit) > > > > (define-syntax (definer stx) > > (syntax-case stx () > > [(_ id) > > #'(definer id zam)] > > [(_ id arg) > > (with-syntax ([arg-id (format-id stx "~a-~a" #'arg #'id)]) > > #'(begin > > (define id (quote id)) > > (define arg-id (quote arg-id))))])) > > > > > > (definer foo-id bar) > > (check-equal? foo-id 'foo-id) > > (check-equal? bar-foo-id 'bar-foo-id) > > > > (definer baz-id) > > (check-equal? baz-id 'baz-id) > > (check-equal? zam-baz-id 'zam-baz-id) ;; unbound identifier error > > > > > > OTOH, this version of the macro, which repeats the expansion template > rather > > than calling itself, works fine: > > > > > > #lang racket > > (require (for-syntax racket/syntax) rackunit) > > > > (define-syntax (definer2 stx) > > (syntax-case stx () > > [(_ id) > > (with-syntax ([arg-id (format-id stx "~a-~a" (format-id stx "zam") > #'id)]) > > #'(begin > > (define id (quote id)) > > (define arg-id (quote arg-id))))] > > [(_ id arg) > > (with-syntax ([arg-id (format-id stx "~a-~a" #'arg #'id)]) > > #'(begin > > (define id (quote id)) > > (define arg-id (quote arg-id))))])) > > > > > > (definer2 foo-id bar) > > (check-equal? foo-id 'foo-id) > > (check-equal? bar-foo-id 'bar-foo-id) > > > > (definer2 baz-id) > > (check-equal? baz-id 'baz-id) > > (check-equal? zam-baz-id 'zam-baz-id) ;; no error this time > > ____________________ > > Racket Users list: > > http://lists.racket-lang.org/users >
____________________ Racket Users list: http://lists.racket-lang.org/users