Re: hygiene when using multiple instances of a macro..?
Panu
(08 Aug 2005 14:22 UTC)
|
Re: hygiene when using multiple instances of a macro..?
Andre van Tonder
(08 Aug 2005 14:55 UTC)
|
Re: hygiene when using multiple instances of a macro..? Keith Wright (09 Aug 2005 02:28 UTC)
|
Re: hygiene when using multiple instances of a macro..?
Andre van Tonder
(09 Aug 2005 11:49 UTC)
|
Re: hygiene when using multiple instances of a macro..?
Panu A. Kalliokoski
(09 Aug 2005 07:00 UTC)
|
Re: hygiene when using multiple instances of a macro..?
Andre van Tonder
(09 Aug 2005 13:53 UTC)
|
> From: Andre van Tonder <xxxxxx@now.het.brown.edu> > > Thank you for the example, but shouldn't that be instead: > > (define-syntax (can-we-stand-duplicates a-macro) > (quasisyntax > (if ',a-macro ; note quote > (let ((x 3)) (,a-macro #f)) > x))) > > (test) ;==> reference to unidentified identifier: x#top > On Mon, 8 Aug 2005, Panu wrote: > > > ... if it works wrong, it expands to (something that evaluates to) 3. > > If it works right, it expands to something that has an unbound > > identifier. I didn't see why the quote is needed, so I ran the original example. When I got an undefined identifier I thought all was well, and was about to post a defence of Panu. Then I noticed it was the _wrong_ undefined identifier. After an afternoon of breaking things and fixing them again I was a happier but wiser man. In the course of my adventures I noticed the following code in the reference implementation. (define (expand-define-syntax t) (let ((t (normalize-definition t #t)) (r (make-primitive-renaming-procedure))) (bind-toplevel! (cadr t)) `(register-macro ',(binding-name (cadr t)) ,(expand (caddr t))))) This expands a form like (define-syntax (test) #`(can-we-stand-duplicates can-we-stand-duplicates)) into a call to the |register-macro| procedure called with something that looks like ((lambda (@test_406) (lambda (@form_407) (apply @test_406 @form_407))) ; make |test| take zero args (lambda (@dummy_408) ; make a renamer to apply to all ids in the quasisyntax (let ((rename_412 (make-meta-renaming-procedure))) ; build the syntax list out of renamed ids (cons (rename_412 (quote _) (quote can-we-stand-duplicates) (quote can-we-stand-duplicates_) (quote __417)) (cons (rename_412 (quote _) (quote can-we-stand-duplicates) (quote can-we-stand-duplicates_) (quote __417)) (quote ())))))))) It is then left to the execution phase of the reepl (read-expand-execute-print loop) to evaluate that lambda expression and register it in the *syntax-environment*. Since the reepl always evaluates the top-level form right after expanding it, this gets the correct result in the end, but if you wanted your expand phase to produce an expanded form that could be executed separately, then this would be wrong. You would want you lambda form evaluated to a procedure and registered _by the expander_. On the other hand, I was having so much fun looking at the raw lambda expressions that I did not want to evaluate them before I could see them. So I changed it to: (define (expand-define-syntax t) (let ((t (normalize-definition t #t)) (r (make-primitive-renaming-procedure))) (bind-toplevel! (cadr t)) (let ((proc-source (expand (caddr t)))) (register-macro (binding-name (cadr t)) (eval proc-source)) `(registered-macro ',(binding-name (cadr t)) ',proc-source)))) (define (registered-macro name proc) (void)) This evaluates and registers the transformer procedure in the expander phase and expands to something that does nothing and yields void at execution time. But it does nothing in a way that is fun to watch. By the way, my transformer procedure looks a bit different from yours because I had to change all the sharp signs #\# in the identifiers into underscores so that my Scheme could read them. I have a reepl like procedure that goes through the file of test cases and compares against the correct answers. -- -- Keith Wright Programmer in Chief, Free Computer Shop --- Food, Shelter, Source code. ---