They're what first-class functions are to functions. That is, the ability to create anonymous macros and pass them around as first-class objects. Imagine you could do something like
(let m (macro (x) `(foo ,x))
...)
or
(map (macro (x) `(= ,x 'blah)) xs)
It's like the difference between having fn and just having def. Right now we only have mac and no way to reference macros as their own entity.
arc> ((annotate 'mac (fn (x) x)) 'x)
Error: "Function call on inappropriate object #(tagged mac #<procedure>) (x)"
Whenever the topic resurfaces, the word seems to be the same: they still make compilation difficult (the most recent research only seems to be from 2000 or so http://lambda-the-ultimate.org/node/2987) and pg has yet to comment on them. So to implement first-class macros currently, you'd probably effectively turn ac into an interpreter so that macros could expand at run-time.
That example specifically? It was nonsense. My point was that you could, say, map macros (anonymous or not). Those used to inline functions, for instance: you want to use a macro like a function, but it's a macro for efficiency. Currently, you have to wrap it in a function, which is kludgey.
Silly example:
; instead of
(map complement list-of-fns)
; you have to do
(map [complement _] list-of-fns)
Again, macros being first-class intuitively works like functions being first-class. So, with first-class macros you could have expressions return macros.
(mac m ...)
((traced m) ...) ; traced is a higher-order function
; since m is a macro, (traced m) returns a macro
More popularly, Bawden's paper (http://people.csail.mit.edu/alan/mtt/) demonstrates writing a module system with first-class macros in which the modules are also first-class.
I think the example was supposed to set all of the variable names contained in the list xs to contain the value 'blah.
The example wasn't supposed to do anything. I was just foo-bar-baz-ing something. I don't think the example would actually do that anyways, for the same reason the following doesn't work.
arc> (mac m (x) `(= ,x 'blah))
#(tagged mac #<procedure: m>)
arc> (m 'a)
Error: "reference to undefined identifier: _quote"
I guess it would've alleviated confusion had I said
Well, first class macros don't work right now anyway, so I wasn't expecting your example to work. I was just trying to figure out the idea behind the example.
And I think that first class macros would be required to set an arbitrary list of variables to contain an arbitrary list of values via map. Obviously with or let would work in a local scope, but if you want global variables you'd need something like that, or at least a function that wraps the macro.
Oh, do you mean you want access to the lexical environment at run time? That sounds like to me more like you want the lexical environment to be a first class object.
The lexical environment is (mostly) accessible at run time. The problem is when you're returning a macro from a function, instead of just renaming it.
Suppose you implement packages as tables of symbols. Suppose also that you have a macro stored in said package. There are two ways to use the macro
1.
(= newmac package!newmac)
(newmac args)
2.
(package!newmac args)
I think that most people would like to use the second form, because it doesn't require importing the macro into the current namespace. Unfortunately, the second version requires first class macros.
Obviously, since the compiler can't easily determine that an expression is going to be a macro, it won't have the advantage of compile time optimization. I'm not sure how important that is. Given that arc is already a "slow" language, why not give it more expressive power at the cost of slightly lower speed? Especially since the user can choose whether or not to use them.
So, as I see it first class macros give you several features:
1. easy to make a package system that can contain macros
2. macros fit in better with functions; no wrapping of macros in functions
3. anonymous macros created for mapping across expressions, etc.
evaluation of expr2 and expr3 can be delayed until after expr1 is evaluated. If expr1 turns out to evaluate to a macro, then the literal expr2 and expr3 can be passed to the macro.