[plt-scheme] depth of macro expansion in module during module require?
Yin-So Chen skrev:
> Hi Jens -
>
> thanks for the quick reply. After some more researching plus looking at
> your code I realized where my mistakes are - I thought symbols in a
> syntax expands out to itself, but apparently this is not the case (hence
> my problem has nothing to do with module/macros). Instead, I need to
> use datum->syntax-object to make sure that timeout in syntax equals
> timeout in symbol (BTW - thanks for your example showing below using stx
> as the context syntax... I was scratching my head trying to figure out
> where I can provide a context).
>
> However, looking at your code there are some concepts that I don't
> understand:
>
> * your code provides syntax name for time-out and main rather than
> timeout, start, initial-request, and interface-version - why this
> also works without having to convert them to syntax-object?
Section 12.3.5 "Macro-Generated Top-Level and Module Definitions"
contains the explanation.
<http://download.plt-scheme.org/doc/360/html/mzscheme/mzscheme-Z-H-12.html#node_sec_12.3.5>
In provide (see section 5.2), for a provide-spec of the form
identifier, the exported identifier is the one that binds identifier
within the module in a generator-specific way, but the external name
is the plain identifier.
...
For all-defined and all-defined-except, only identifiers with
definitions having the same generator as the all-defined or
all-defined-except keyword are exported; the external name is the
plain identifier from the definition. The generator of an all-from or
all-from-except provide-spec does not affect the set identifiers
exported by the provide-spec.
So (provide (all-defined)) will only provide names defined by the *same
macro expansion*. That's why it is convenient to expand into
(begin
(define name 'foo)
(provide foo))
if one want to make sure name is to be provided.
> * how does the nested define-syntax work both in terms of expansion
> and scoping?
In my version
(servlet
(time-out +inf.0)
(main `(p "hello world")))
is first expanded into
(begin
(define-syntax (time-out stx) ...)
(define-syntax (main stx) ...)
(time-out +inf.0)
(main `(p "hello world"))
(define interface-version 'v1)
(provide (all-defined)))
Then this is expanded. Since the (syntax) definition of main precedes
the macro use (main ...), there are no scope problems.
> * Aesthetics and styles aside - is there a reason for nested
> define-syntax? (It looks cool to learn, but I came from the C
> world where definitions belong on top level, so want to know why
> and how I can think in this fashion)
An alternative is to use a helper module:
(module syntax-helper mzscheme
(define-syntax (time-out stx) ...)
(define-syntax (main stx) ...)
(provide (all-defined)))
and then use
(define-syntax servlet
(lambda (stx)
(syntax-case stx ()
((_ body ...)
(with-syntax ([time-out (datum->syntax-object stx 'time-out)]
[main (datum->syntax-object stx 'main)])
#`(begin
(require "syntax-helper.scm")
body ...
(define interface-version 'v1)
(provide (all-defined))))))))
[At least I think so, this time I didn't test]
--
Jens Axel Søgaard