The following message is a courtesy copy of an article that has been posted to comp.lang.scheme as well. This response to a SRFI-46 mailing list message is being posted to comp.lang.scheme and CC'ed to the list. Taylor Campbell wrote: > The directive mechanism is a general method for letting expanders > arbitrarily extend SYNTAX-RULES without hacking kludge after kludge > onto it in a haphazard manner. ... > let me first state that this is just a preliminary idea: it popped > into my brain early this afternoon and I mentioned it to #scheme > (where both of those responses were generated), without any formal > document describing it, any ideas to turn SRFI 46 into a > SYNTAX-RIASTRADH specification, the thought of sending it to the > (to-be-chosen) R6RS authors, or anything like that; it was just an > idea that popped into my head to generalize all the modifications > that are being considered to SYNTAX-RULES and all of the possible > future modifications, without continually adding disgusting kludges > and tacking on some new variant of SYNTAX-RULES whenever someone > thinks something up. You seem to think that the significant part of your proposal is the switch to using keyword-tagged arguments instead of positional ones. I don't think that's a very radical idea. I also think that the (syntax-rules <ellipsis>? <literals> <rule>*) calling convention is simple enough that switching to a keyword arg list is not necessary (it's no more complicated than named LET, and people seem okay with that). However, adding an additional optional argument (like UNHYGIENE), probably would push the complexity to the point where switching to keywords would make sense. The much more radical part of your proposal is the support for inserting identifiers unhygienically. Are you sure you want to open that can of worms? Unhygienic insertion really is a dirty and dangerous business (I've even heard people say it can give you AIDS, but they might have been talking about something else). This SRFI started as a codification of some simple existing practice, namely (... ...). Then it switched to a new, relatively simple but untested feature, Choose-Your-Own-Ellipsis. Now you are talking about making a major design change that can require significant implementation effort (eiod and alexpander, for example, would need to change their whole identifier models to be able to support unhygienic identifier creation properly) and for which there is no practical experience. > All I'm doing is putting the idea up for comment. I hate to get all Bradd W. Szonye on you, but I have to say that perhaps a SRFI mailing list is the wrong forum in which to put this idea up for comment. Maybe you should withdraw the SRFI, discuss possible designs on comp.lang.scheme, implement some of them and see how well they work, and then submit a SRFI. Okay, so now I will proceed to discuss the issues, here in comp.lang.scheme. As for the name, I was thinking that, in light of unhygienic macros' tendency to bite one on the ass, maybe a warning exclamation point should be in the name of any hygiene-breaking macro generator. Hence, SYNTAX-ATTACKS! (with the all-caps version officially encouraged), or syntax-rules-are-made-to-be-broken!, or simply syntax-r0OLZ-D00D!!!. Doc Shriram said in <w7dznedh9xxxxxx@cs.brown.edu> on comp.lang.scheme: > your UNHYGIENE looks distinctly inferior to the version in > SYNTAX-CASE. When you capture IT in IF-IT, how do you tell it what > the scope of IT is meant to be? This is one of the problems that > SYNTAX-CASE addresses with extraordinary elegance, and you don't > seem to be addressing it at all! I don't think datum->syntax-object's elegance is extraordinary, and in fact I think it is a little bit broken with respect to macro-producing macros, and below I will propose a less-broken, more-elegant version that could work with syntax-attacks!. First, however, I will elaborate on the problem Shriram is talking about. Consider two macros you might want to write that use your IF-IT: WHEN-IT and OR2. (WHEN-IT <test> <expr>+) evaluates <test> and, if the result is not #f, evaluates each <expr> in sequence with IT bound to the result. (OR2 <expr1> <expr2>) is just like standard OR, but must be given exactly two arguments. (define-syntax if-it (syntax-attacks! ((unhygiene make-unhygienic)) ((if-it test then else) (let (((make-unhygienic it) test)) (if (make-unhygienic it) then else))))) (define-syntax when-it (syntax-rules () ((when-it test expr ...) (if-it test (begin expr ...) (if #f #f))))) (define-syntax or2 (syntax-rules () ((or2 expr1 expr2) (if-it expr1 it expr2)))) When-it works fine, but when or2 calls if-it, if-it inserts a binding for IT that *won't* capture the renamed IT inserted by or2, and *will* capture any uses of IT in expr2. We can fix the first problem like so: (define-syntax or2 (syntax-attacks! ((unhygiene ick!)) ((or2 expr1 expr2) (if-it expr1 (ick! it) expr2)))) but this still leaves the problem of (let ((it 1)) (or2 #f it)) evaluating to #f (the value to which if-it binds IT), when it should evaluate to 1. To fix this in the manner that the syntax-case system does, you would make the unhygiene operator (our equivalent of datum->syntax-object) take two arguments (the first one being an identifier whose coloring should be copied to the second), and have macro invocation pass to the macro the identifier that was bound to the macro. Then the macros could be written like so: (define-syntax if-it (syntax-attacks! ((unhygiene ick!)) ((_ test then else) (let (((ick! _ it) test)) (if (ick! _ it) then else))))) (define-syntax when-it (syntax-attacks! ((unhygiene ick!)) ((_ test expr ...) ((ick! _ if-it) test (begin expr ...) (if #f #f))))) (define-syntax or2 (syntax-rules () ((or2 expr1 expr2) (if-it expr1 it expr2)))) In practice (assuming we do not allow identifier concatenation), I think the first argument to the unhygiene operator will always be the identifier that was used to invoke the macro. (That statement might be way off: someone with more syntax-case experience please correct me if so, and provide motivation for other first arguments to datum->syntax-object.) Therefore, we can make syntax-attacks! automatically do this. Then you do away with the first argument to the unhygiene operator, and also do away with the need to actually bind the first element of the pattern to anything. That reduces our macros to this: (define-syntax if-it (syntax-attacks! ((unhygiene ick!)) ((if-it test then else) (let (((ick! it) test)) (if (ick! it) then else))))) (define-syntax when-it (syntax-attacks! ((unhygiene ick!)) ((when-it test expr ...) ((ick! if-it) test (begin expr ...) (if #f #f))))) (define-syntax or2 (syntax-rules () ((or2 expr1 expr2) (if-it expr1 it expr2)))) Now, let me get back to my problem with datum->syntax-object. It demands that the second argument be a datum stripped of all marks, but I think the right thing to do sometimes is to add marks to an identifier that might already have some. To enable this, datum->syntax-object should allow you to pass it three arguments -- two identifiers and a syntax object -- where the second identifier would always be the same identifier as the first identifier, but possibly with some extra marks, and these extra marks would be added to any identifiers in the syntax object. In the syntax-attacks! system we could have both of the identifier arguments generated automatically: they would be the identifier that was bound to the macro and the identifier that was used in the macro call. How did I reach this conclusion? I've run out of time to say. I'm afraid I've been "between unemployments" for a whole year now, and it's really cut back on the time I devote to macrological minutiae. Fortunately, my long nightmare of personal prosperity will probably end in January and then I'll be able to dive deeply into this issue until my sanity boils over. -al