Whoa, very nice!<br><br>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.<br>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.<br>
It is definitely better.<br>
<br>Also, the first let () is not really needed I guess.<br><br>Thank you very much.<br>Laurent<br><br><div class="gmail_quote">On Mon, Apr 18, 2011 at 20:42, Jon Rafkind <span dir="ltr"><<a href="mailto:rafkind@cs.utah.edu" target="_blank">rafkind@cs.utah.edu</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div text="#000000" bgcolor="#ffffff">
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.<br>
<br>
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.<br>
<br>
#lang racket<div><br>
<br>
(define-syntax (define-syntax-rule/id stx)<br>
(syntax-case stx ()<br></div>
[(_ (name arg ...)<br>
[id id-rename]<br>
body ...)<br>
(let ()<br>
#'(define-syntax (name stx)<br>
(syntax-case stx ()<br>
[(_ arg ...)<br>
;; we want the defined procedure to have the same
lexical scope as<br>
;; the arguments given to the syntax-rule<br>
;; we can't use #'(arg ...) as the thing to get the
lexical scope<br>
;; because #' will create a new syntax object using the
lexical<br>
;; scope of the code right here. so instead we take out
the first<br>
;; object from the argument list which should have the
right scope.<br>
(with-syntax ([id (datum->syntax (car
(syntax->list #'(arg ...)))<br>
(string->symbol<br>
(let ([arg (syntax-e
#'arg)] ...)<br>
id-rename))<br>
(car (syntax->list
#'(arg ...))))])<br>
#'(begin body ...))]))<br>
)]))<br>
<br>
(define-syntax-rule/id (make-getter xid)<br>
[id2 (format "get-~a" xid)]<br>
(define (id2) xid))<br>
<br>
(define x1 5)<br>
(make-getter x1)<br>
(get-x1)<div><div></div><div><br>
<br>
<br>
On 04/18/2011 12:03 PM, Laurent wrote:
</div></div><blockquote type="cite"><div><div></div><div>Found!<br>
<br>
After having read more carefully Eli's very good post (<a href="http://blog.racket-lang.org/2011/04/writing-syntax-case-macros.html" target="_blank">http://blog.racket-lang.org/2011/04/writing-syntax-case-macros.html</a>),
it became clearer that the problem was that the context of the
created identifier was wrong.<br>
Deconstructing and reconstructing the id syntax object did the
trick:<br>
<br>
(define-syntax (define-syntax-rule/id stx)<br>
(syntax-case stx ()<br>
[(_ [id id-gen] body)<br>
(with-syntax ([id-def (to-syntax <br>
(syntax-e (syntax-local-eval
#'id-gen))<br>
#:stx stx)])<br>
#'(splicing-let-syntax ([tmp-form (syntax-rules ()<br>
[(_ id) (begin (displayln 'body)<br>
body)])])<br>
(tmp-form id-def))<br>
)]<br>
))<br>
<br>
<br>
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.<br>
<br>
Thanks for listening :)<br>
Laurent<br>
<br>
<br>
<div class="gmail_quote">On Mon, Apr 18, 2011 at 18:21, Laurent <span dir="ltr"><<a href="mailto:laurent.orseau@gmail.com" target="_blank">laurent.orseau@gmail.com</a>></span>
wrote:<br>
<blockquote class="gmail_quote" style="margin:0pt 0pt 0pt 0.8ex;border-left:1px solid rgb(204, 204, 204);padding-left:1ex">
Dear Racket list,<br>
<br>
Once again, I need a little help on a macro definition.<br>
<br>
I want to define the following (simplified[1]) macro:<br>
(define-syntax-rule/id [<i>id id-gen</i>] <i>body</i>)<br>
<br>
where id is replaced with the result of id-gen inside body.<br>
For example:<br>
(define-syntax-rule/id <br>
[x #'foo]<br>
(begin (define x 5)<br>
(displayln x)))<br>
<br>
is supposed to bind foo to 5 in the top-level at run-time.<br>
(You can replace #'foo by some complex identifier-making
expression using format-id.)<br>
Here is what I have right now, after much trial&error:<br>
<br>
#lang racket<br>
<br>
(require (for-syntax unstable/syntax)<br>
(for-syntax errortrace/errortrace-key)<br>
racket/splicing<br>
)<br>
<br>
(provide (all-defined-out))<br>
<br>
;; Like define-syntax-rule,<br>
;; but id is replaced with the result of id-gen in body.<br>
;; id-gen is eval'ed at macro-time.<br>
(define-syntax (define-syntax-rule/id stx)<br>
(syntax-case stx ()<br>
[(_ [id id-gen] body)<br>
(with-syntax ([id-def (syntax-local-eval #'id-gen)])<br>
#'(splicing-let-syntax ([tmp-form (syntax-rules ()<br>
[(_ id) (begin (displayln
'body)<br>
body)])])<br>
(tmp-form id-def))<br>
)]<br>
))<br>
<br>
;;; TESTS<br>
<br>
(define-syntax-rule/id <br>
[x #'foo]<br>
(begin (define x 5)<br>
(displayln x)<br>
(displayln 'x)<br>
))<br>
<br>
<br>
It works (foo is bound to 5), except that foo is unknown
(undefined identifier) after the (begin ...).<br>
I suspect this is because of syntax-local-eval, but I don't
know what to use instead.<br>
<br>
There is another intriguing thing:<br>
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!<br>
Why is that and why does this not work when there is no
(provide x) ? [note that there is a (provide (all-defined
out)).]<br>
<br>
Can someone give me a hint as to what is going on?<br>
<br>
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.<br>
<br>
Thank you very much,<br>
Laurent<br>
<br>
<br>
[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:<br>
<br>
(define-syntax-rule/id (make-getter id)<br>
[id2 (format-id #'here "get-~a" id)]<br>
(define (id2) id))<br>
<br>
which, when called on (make-getter foo) would create the
get-foo function.<br>
</blockquote>
</div>
<br>
</div></div><pre><fieldset></fieldset>
_________________________________________________
For list-related administrative tasks:
<a href="http://lists.racket-lang.org/listinfo/users" target="_blank">http://lists.racket-lang.org/listinfo/users</a></pre>
</blockquote>
<br>
</div>
<br>_________________________________________________<br>
For list-related administrative tasks:<br>
<a href="http://lists.racket-lang.org/listinfo/users" target="_blank">http://lists.racket-lang.org/listinfo/users</a><br></blockquote></div><br>