[plt-scheme] Introducing an Identifier into the Lexical Conte xt of a Macro Cal l
The with-syntax is more appealing. In my case, I am generating a let to
introduce a variable around a body of code from the macro call. I assume
that generating the identifier in the context of the body would address the
macros expanding to non-hygienic macros issue (at least in most cases).
Is there a good example anywhere of similar code in PLT Scheme? Generating
a 'self' variable for class methods would be an example that comes to mind.
Doug
P.S. And here I thought I knew LISP (and, therefore, Scheme) already. :^)
> Jens Axel Søgaard wrote:
>
>
> Williams, M. Douglas wrote:
> > The PLT Scheme Reference Manual contains the following example in
> > section 12.2.1:
>
> > ---
> >
> > Another reason to use syntax-case is to implement ``non-hygienic''
> macros
> > that introduce capturing identifiers:
> >
> > (define-syntax (if-it stx)
> > (syntax-case stx ()
> > [(src-if-it test then else)
> > (syntax-case (datum->syntax-object (syntax src-if-it) 'it) ()
> > [it (syntax (let ([it test]) (if it then else)))])])))
> > (if-it (memq 'b '(a b c)) it 'nope) ; => '(b c)
> >
> > ---
> >
> > Is this the best way to introduce an identifier ('it' in this case) into
> the
> > lexical context of the macro's use?
>
>
> Later in the manual there is an example I like better:
>
> (define-syntax (if-it stx)
> (syntax-case stx ()
> [(src-if-it test then else)
> (with-syntax ([it (datum->syntax-object (syntax src-if-it) 'it)])
> (syntax (let ([it test]) (if it then else))))])))
>
> Right after that example comes:
>
> --- quote start ---
>
> Macros that expand to non-hygienic macros rarely work as intended. For
> example:
>
> (define-syntax (cond-it stx)
> (syntax-case stx ()
> [(_ (test body) . rest)
> (syntax (if-it test body (cond-it . rest)))]
> [(_) (syntax (void))]))
> (cond-it [(memq 'b '(a b c)) it] [#t 'nope]) ; => undefined variable it
>
> The problem is that cond-it introduces if-it (hygienically), so
> cond-it effectively introduces it (hygienically), which doesn't bind
> it in the source use of cond-it. In general, the solution is to avoid
> macros that expand to uses of non-hygienic macros. (32)
>
> (32) In this particular case, Shriram Krishnamurthi points out
> changing if-it to use (datum->syntax-object (syntax test) 'it) solves
> the problem in a sensible way.
>
> --- quote ends ---
>
> Suppose for arguments sake that if-it were provided by an external
> module, and that you couldn't change it. How should cond-it be
> defined?
>
> The only working solution I could find were:
>
> (define-syntax (cond-it stx)
> (syntax-case stx ()
> [(src-cond-it (test body) . rest)
> (let ((if-it-transformer (syntax-local-value #'if-it))
> (if-it-stx (datum->syntax-object (syntax src-cond-it)
> 'if-it)))
> (if-it-transformer #`(#,if-it-stx test body (cond-it . rest))))]
> [(_) (syntax (void))]))
>
> Is there a simpler solution?
>
>
> Here is the entire example with tests (that breaks with all the simpler
> attempts I tried):
>
>
> (module if-it mzscheme
> (provide if-it)
>
> (define-syntax (if-it stx)
> (syntax-case stx ()
> [(src-if-it test then else)
> (with-syntax ([it (datum->syntax-object (syntax src-if-it) 'it)])
> (syntax (let ([it test]) (if it then else))))])))
>
> (module cond-it mzscheme
> (provide cond-it)
> (require if-it)
> ;(require-for-syntax if-it)
>
> (define-syntax (cond-it stx)
> (syntax-case stx ()
> [(src-cond-it (test body) . rest)
> (let ((if-it-transformer (syntax-local-value #'if-it))
> (if-it-stx (datum->syntax-object (syntax src-cond-it)
> 'if-it)))
> (if-it-transformer #`(#,if-it-stx test body (cond-it . rest))))]
> [(_) (syntax (void))])))
>
> (require cond-it)
>
> (cond-it
> [#t it]
> [#t 'nope])
>
> (let ((it 42))
> (cond-it
> [#t it]
> [#t 'nope]))
>
> (let ((if-it 43))
> (let ((it 42))
> (cond-it
> [#t it]
> [#t 'nope])))
>
> (cond-it ((memq 'b '(a b c))
> (let ((it0 it))
> (if-it (memq 'y '(x y z))
> (values it0 it)
> 'nope0)))
> (#t 'nope1))
>
> (require if-it)
>
> (cond-it
> [#t it]
> [#t 'nope])
>
> (let ((it 42))
> (cond-it
> [#t it]
> [#t 'nope]))
>
> (let ((if-it 43))
> (let ((it 42))
> (cond-it
> [#t it]
> [#t 'nope])))
>
> (cond-it ((memq 'b '(a b c))
> (let ((it0 it))
> (if-it (memq 'y '(x y z)) (values it0 it) 'nope0)))
> (#t 'nope1))
>
>
> --
> Jens Axel Søgaard
>