True. What about ehird's variation (from the same thread)? It's a little more complex but should accomplish what you're looking for, since all the work is done at read time.
Didn't try it tho, so give it a spin and let us know ^_^
Well, pretty much any solution involving a macro isn't going to do what I want. By necessity, calling a macro requires parentheses and a token. My solution just changes two parentheses to curly braces and requires no extra tokens. It will always be more lightweight than any macro solution. That's the main goal of my feature.
Wow, that's true! I don't use aand much so I didn't notice. Shorting on nil can definitely be a problem because sometimes you want to do something different; it's not very readable since "aand" suggests a boolean result; finally, my macro could be modified in different ways that diverge from the usual aand semantics (like having a special form to break from the pipeline).
Truly innovative, pure hacker style. But it is also true that anonymity can make people a little more... daring. I think a registration form could be a good step towards sanity: a login makes people think twice, which is usually a good thing. Just a suggestion, see if it suits you.
I'd like to point out that this problem happens even when you don't redefine primitives or core functions. I read somewhere (maybe even one of PG's books, can't remember) that this is one of the reasons why Common Lisp is a LISP-2: because of unhygienic macros.
This is especially relevant when you use many libraries: it's not possible to remember all of their exported symbols and sooner or later you are going to shadow one of them. It only takes one macro call, then, to trigger a possibly very tricky bug.
This is made even worse by Arc's special syntax: if a variable contains a string or a hash instead of a unary function, this won't be detected until much later. So this problem seem to be more relevant to larger programs.
Is there a more elegant workaround? Does the devteam has something in mind?
I agree. macro transformers would need to refer to the lexical context in which they were defined. strangely, a number of threads in this forum seem to indicate substantial resistance against implementing Arc macros any way other than as simple list manipulations. now granted that 1) straightforward list transformations are easy to understand, 2) there are limitations with _some_ macro systems that provide for lexical references to identifiers in the definition context, 3) inadvertently shadowing identifiers appearing in macroexpansions is unlikely in _other_ Lisps thanks to multiple namespaces, package systems and restrictions on shadowing certain identifiers, and 4) it is a lot more difficult to correctly implement a macro system that solves this problem. however, let's all agree that a hypothetical macro system that _could_ solve this problem would be vastly preferable. arguing against this on the grounds that accidentally shadowing identifiers is a problem you're willing to deal with manually (in a single-namespace Lisp with no module system and no shadowing restrictions) is analogous to arguing in favor of dynamic scoping over lexical scoping as a sensible default.
Unhygienic is shorter byte-wise and token-wise. But they are not so different, are they? If you need to prevent variable capture for some symbols, you need one more line with with-gensyms and the symbols to protect. Easy enough.
Otherwise, please provide some real code to talk about.
To make it perfectly clear, I am not advocating Scheme's implementation of hygienic macros. I am merely pointing out with-gensyms is such a common pattern it would make sense to abstracted it away. Furthermore we already have such an abstraction, it is called hygienic macros.
In a language where commonly used names are abbreviated to save a character or two, "one more line" of boiler-plate should not be accepted at face value.
Ideally hygienic macros would look exactly the same as unhygienic with some clever transformations behind the scenes. For instance instead of
(mac complement (f)
(let g (uniq)
`(fn ,g (no (apply ,f ,g)))))
one would write:
(hmac complement (f)
`(fn g (no (apply ,f g)))))
and macro hmac would do the rest (probably arriving at something resembling the former).
1. with-gensyms (or w/uniq in Arc) is not so common. I recently wrote a (small) application in Common Lisp and less than 50% of the macros need it. Same thing for once-only.
2. Yes, it would be a great thing to abstract that boilerplate away... if it was possible. I think Scheme developers aren't stupid. If it were easy to make a macro system that works like yours, it would probably already exist. As it's been argued, hygienic macros tend to make variable-capture much harder when you need it. And sometimes you need it a lot (e.g. DSL). Again: in my application, about 40% of macros capture a symbol, usually to make things shorter.
1. I didn't know that, I never managed to get past that point. :P Are there macros like with-gensyms that make your life easier? Could you give a reference to show more precisely what you mean? That would be really nice.
2. What I mean is that variable capture is even more useful in big projects (because the DSL approach tends to be more powerful). It is true that they could cause nastier bugs if used incorrectly. But if you use them correctly (by forcing an order of evaluation and protecting the variables you use) there should be no problems. That's certainly true for a LISP-2, I'm not sure about Arc.
3. I don't care how you call it: if you use gensyms where needed the resulting macros won't screw you up! That's what matters, doesn't it?
1. You complained about scheme having too much boilerplate code. This is easy to fix, for example, with this macro-defining-macros:
((defmac (name x ...) body)
(syntax-rules () ((name x ...) body))))))
you can write:
(defmac (unless condition body ...)
(when (not condition) body ...))
(See also item 4.)
2. Yes, DSLs are even more useful in big projects; obviously, the only source of all problems is using something incorrectly, the problem is how easy it is to write something incorrect; evaluation order has nothing to do with macros; protecting variables you use doesn't cover all problems; lisp-2 is "statistically better" because people shadow function names less frequently (see also next item).
3. They will bite -- even if you always use gensyms. A simple example:
4. Extra point: doing simple captures in scheme with `define-syntax' is said to be difficult in the general case, but it is possible to make that easy too. For example, see the macro definition and examples in http://tmp.barzilay.org/defmac.ss -- the definition uses mzscheme's `syntax-case' etc, but this is not something that you should know about to use it. Just skip to the example to see how it works. (Cheat: there are subtle cases that this doesn't work.)
2. "the problem is how easy it is to write something incorrect". Very true.
"evaluation order has nothing to do with macros" I'm sorry but that's incorrect. An example will show you why:
(mac sum (x y) `(+ ,y ,x)) ; This is a toy, but some macros suffer from the same problem without being so trivial/stupid
(= x 1)
(+ x (++ x)) ; -> 3, the expected result
(= x 1)
(sum x (++ x)) ; -> 4, wrong result
Common Lisp macros usually solve this with a meta-macro called once-only that forces things to be evaluated in the right order and only once. Google it for more info.
"lisp-2 is statistically better". Well, not if people know that shadowing function can cause problems. Now a question arises: does shadowing functions solve problems in a way not possible with other methods? Does shadowing function make programs shorter? Or, equivalently, is shadowing functions really that useful? (Please provide examples if you answer this). If not, using a lisp-2 and being careful is enough. But yes, it's easy to overlook a symbol and make a mistake that can be costly. On that, I agree.
3. You are right and that's why I said "I'm not sure about [a lisp-1 like] Arc".
4. That seems really interesting, I'll look into it.
One of the things that you can do with macros is specify evaluation order, that's correct. You should also know when and how to evaluate your arguments, as done with the once-only utility (which is really just a thin wrapper around the obvious solution of binders).
But when I said "evaluation order has nothing to do with macros" I meant the kind of macro facility that you use (the original context of this thread was hygiene). No matter which kind of macros you have, the above issues are still the same.
1. Seems unimportant to me. Probably it's mostly an aesthetical matter, thus very subjective.
2. I like the default. Macros are hard and the last thing I wanna do is learn TWO macro systems. Also, I really can't get scheme-style macros. They just won't click.
"Turning off" variable capture is pretty straightforward once you get it. And there are tools that can help you do it easily. It's not the most convenient thing in the world, I admit, but it's good enough for me.
3. Yes, I like uniformity too. Why not `(a b . ,others) instead? Would be more similar to what we do elsewhere. Oh, well...