[cc user@ again] There is no bug in syntax-rule/s.
Macros do not evaluate anything. They rewrite code. Code refers to identifiers. This relation must remain apparent. That's it. -- Matthias On Jan 14, 2015, at 9:57 PM, Thomas Lynch wrote: > As for the demonstrative example at the top of the original post, I now > understand you are speaking of clarity and style rather than a functional > problem with it. I enjoyed that discussion on clarity, intention, and > aesthetics. > > As for the question of why the 'body' argument is being evaluated as an > operand rather as part of the expansion, and thus resulting in an undefined > identifier error, am I correct to read your answer above, that this is indeed > a bug? "macro-site variables are bound by macro-contexts" but clearly that > is not happening - or the error wouldn't be issued. > > IMHO the define-syntax-rule would be the clearest implementation for the > reader for the reasons you give. Too bad there is a bug in it. (The operand > should not be evaluated except as part of the macro expansion, as you note. > I am reading you on this correctly? I have a hard time understanding why an > operand to a macro would be evaluated before it is included in the expansion, > unless it was a limitation of the interpreter, but if it is a bug, then good > as it can be fixed.) > > On Thu, Jan 15, 2015 at 9:53 AM, Matthias Felleisen <matth...@ccs.neu.edu> > wrote: > > On Jan 14, 2015, at 8:14 PM, Thomas Lynch wrote: > >> Matthias thank you for fielding my question, though two things are not >> clear. I hope you or someone might clarify. >> >> Firstly, is there a reason to prefer the macro you present over the first >> one given in the original post. I believe they both work. Neither uses the >> more elegant syntax-rule. > > > Code that works is fine. Code that clearly explains its intention is better. > Since syntactic extensions are (basically) extensions to the grammar, their > specification ought to bring across (a) what kind of new expressions > programmers may write down and (b) what these new expressions mean. I think > separating these cleanly is also important. > > With syntax-case, which isn't all that different from syntax-rules, you get > (a) easily: > > (with-tables stem body ...) > > Compare this to your three or four lines that stx apart. When your extension > is even more complicated, you definitely want this pattern matching notation > because it is close to the way people write grammars and because you can > automatically check certain properties (see syntax-parse). > > For (b), constructing a piece of syntax manually with backquote, comma, > splice is again much more complicated than writing down a rewrite rule. In > particular, you get a really good handle at the manipulation of scope, which > is one of the primary functions of syntactic extensions. > > Racket like Scheme like Lisp is about being able abstract boiler plate. > Syntax-case abstracts your boiler plate for (a) and (b). > > Ideally, I would like to separate (a) from (b) so that programmers can > specify (a) at the module boundary, just like contracts for functions. That's > what I started Ryan on and we ended up syntax-parse. It' s a fantastic first > step but there is work left to do. Probably another dissertation. > > >> Secondly, and this is the question I'm really getting at, is there a reason >> that the operands given to syntax-rules must have identifiers within lexical >> scope at the point of the macro call, rather than lexical scope at the point >> of their use within the macro? > > Lexical scope is critical for program comprehension. Programmers read > programs a lot more often than they write them. Lexical scope guarantees that > when they read programs all identifiers are resolved (bound) to a declaration > (binding position) that can be found by reading the text -- not running the > program. By finding it in the text w/o running it, you have a better chance > of predicting what the program does when you run it. > > Macros rewrite program text. In the process, they substitute use-site code > into macro-definition code and macro-definition code is substituted into > use-site code. Each substitution may affect lexical scope when performed > without respect to lexical scope. Each substitution may thus bind variables > to binding occurrences that you can only figure out by running code. > Enforcing that > > use-site variables are bound by use-context > macro-site variables are bound by macro-contexts > > ___by default___ is called hygienic expansion and almost always gives you > what you want. > > On rare occasion, an extension of Racket's grammar also needs to break these > default rules. syntax-case/parse allow programmers to break those rules in a > way that is still easy to read off from the code. > > That's why it's the right way to go about syntax extensions. -- Matthias > > > > > > >> >> Off hand the latter seems to be the proper behavior for a macro, i.e. >> perhaps this is a bug? Can anyone here tell me why it behaves like this? >> >> >> On Thu, Jan 15, 2015 at 4:12 AM, Matthias Felleisen <matth...@ccs.neu.edu> >> wrote: >> >> You want something like this: >> >> (define-syntax (with-tables stx) >> (syntax-case stx () >> [(with-tables stem body ...) >> (let ([table-author (datum->syntax stx 'table-author)] >> ;; ... ditto for other identifiers for which you wish to break >> lexical scope >> ) >> #`(let ([table-publication (string-append stem "_publication")] >> [#,table-author (string-append stem "_author")] >> [table-bridge-publication-author (string-append stem >> "_bridge_publication_author")] >> [table-unique-counters (string-append stem >> "_unique_counters")]) >> body ...))])) >> >> (with-tables "x" table-author) >> >> ;; --- >> >> To achieve this with syntax-rules would be, well, hard. >> >> ;; --- >> >> The accepted way of writing this macro is: >> >> (define-syntax (with-tables stx) >> (syntax-case stx () >> [(with-tables stem (table-author >> ;; ... add other names you wish to bind in body >> ) >> body ...) >> #`(let ([table-publication (string-append stem "_publication")] >> [table-author (string-append stem "_author")] >> [table-bridge-publication-author (string-append stem >> "_bridge_publication_author")] >> [table-unique-counters (string-append stem "_unique_counters")]) >> body ...)])) >> >> (with-tables "x" (table-author) table-author) >> >> >> >> > >
____________________ Racket Users list: http://lists.racket-lang.org/users