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

Reply via email to