[plt-scheme] (require... ) expanded from a macro
Matthew Flatt skrev:
> At Sat, 21 Oct 2006 15:52:44 +0200, Jens Axel Søgaard wrote:
>> To break hygiene use syntax-local-introduce:
>>
>> (define-syntax (require-extension stx)
>> (syntax-case stx (srfi)
>> ((_ (srfi n))
>> (number? (syntax-e #'n))
>> (let ([n (syntax-e #'n)])
>> (with-syntax ([name (format "~a.ss" n)])
>> (syntax-local-introduce
>> #'(require (lib name "srfi"))))))))
>
> In this case, I recommend `datum->syntax-object', instead:
>
> (define-syntax (require-extension stx)
> (syntax-case stx (srfi)
> ((_ (srfi n))
> (number? (syntax-e #'n))
> (with-syntax ([path (datum->syntax-object
> #'n
> `(lib ,(format "~a.ss" (syntax-e #'n))
> "srfi"))])
> #'(require path)))))
>
> The `datum->syntax-object' function is more standard and easier to
> reason about. The above use makes `(lib "n.ss" "srfi")' have the same
> lexical context as the original `n', instead of the context of
> macro-introduced syntax. That way, the bindings introduced by `(lib
> "n.ss" "srfi")' will bind in the same context where `n' would have
> bound.
I hope both macros accomplish that.
> `syntax-local-introduce' is a low-level feature that I still only know
> how explain in operational terms (i.e., in terms of the "marks" and
> "renamings" used for syntax-case).
Admitted, I do tend to think of it in terms of marks.
However in the special case where syntax-local-introduce
is applied to a syntax-object constructed by the transformer
containing no parts of the original syntax, I think of it
as "introduce this syntax-object into context of the macro
application".
I.e.
(define-syntax foo
(lambda (stx)
(syntax-local-introduce
#'(require (lib "42." "srfi"))))
and
(define-syntax foo
(lambda (stx)
(datum->syntax-object
stx '(require (lib "42." "srfi"))))
is equivalent (except for the source location info).
To avoid trouble I avoid using syntax-local-introduce on
syntax-objects containing parts of the original syntax.
The main appeal for me, I think, is that "the context of the macro
application" is implicit. It is quite common to see
datum->syntax-object used with the syntax-object representing
the macro application. Also the "introduce" part of the name
syntax-local-introduce indicates the intention better than
datum->syntax-object, which has many uses besides introducing
identifers in the original context.
It is probably a matter of taste, whether it worthwhile
to have a syntax-introduce-identifier.
(syntax-introduce-identifier id-stx)
~ (datum->syntax-object orig-stx id-stx)
(syntax-introduce-identifier id-stx src-loc-stx)
~ (datum->syntax-object orig-stx id-stx src-loc-stx)
[Btw - what is the easiest way to transfer the source-location
from src-loc-stx to id-stx?]
(syntax-introduce-identifier id-stx src-loc prop-stx)
~ (datum->syntax-object orig-stx id-stx src-loc prop-stx)
> Looking at other uses of `syntax-local-introduce' in our code base ...
Another use is preventing additional marking, when a macro embeds return
values of syntax-local-get-shadower in its output.
But syntax-local-get-shadower is rare:
<http://www.scheme.dk/search-plt/search.ss?query=syntax-local-get-shadower>
> In short, use `syntax-local-introduce' when you are cooperating closely
> with the macro expander or managing the macro-expansions of a
> sub-language. I think you should probably avoid it, otherwise.
Sound advice. Low level features ought to be avoided.
> I'm not certain that I've given this advice consistently, in part
> because I'm not entirely sure of the uses myself. Indeed, I'd prefer to
> get rid of `syntax-local-introduce', but something better seems to be
> missing in our syntax system, so that `syntax-local-introduce'
> sometimes seems necessary.
Food for thought.
--
Jens Axel Søgaard