Yes. It's part of good Lisp style not to use a macro when a function would suffice, and yet the source of HN is full of macro calls. If you want to see examples of modern uses of macros, that would be a good place to start.
Not quite, though, because you only want to evaluate the code that gets you to the location once, and the operation needs to be atomic. The actual macroexpansion is much more complicated.
If that's all it does, then I don't see a problem with implementing it in any language without macros. Let's take simple C. (I didn't test it, or even try to compile - just want to show the idea)
Given your explanation: "It lets you apply an arbitrary function[1] to (a variable or a position anywhere within some structure)[2]."
Where object is the structure you're operating on, `selector` is a function taking an object and returning a pointer to the position [2]. The `action` is a pointer to an arbitrary function [1].
By using C you are changing the problem, as your C pointer passes by reference instead of value. The lisp macro works equally well when passing by value, so try rewriting your function to operate on a struct (and, not a struct pointer). It is likely that PG was referring to this functionality when asking how to implement this as a function.
I think you're missing the fact that in the C version you have to write a specialized selector function each time (to find the thing you want to zap), whereas the macro works generically on any place. ("Place" here is an abstraction meaning "settable thing" that is closely related to Lisp macros and is analogous to the left-hand-side of assignment statements in most languages, but far more manipulable by the programmer.)
PG asked "How do you implement that in a language without macros?". I responded with a simplest translation of the example, but a more general solution exists too. Nothing stops me from using GObject instead of void*, which can provide named "places" and as much generic functionality as needed. `selector` and `action` can even operate on property tables, which would be a closer translation from lisp.
I was simply surprised that PG asked about something like that - I still think it's pretty simple and the code in C is as close to the macro as possible (with whatever object abstraction you need).
However I have to admit that I thought about other languages now and it seems that the described zap() is not possible in python... and that's interesting / worrying:
action(object[place])
cannot assign a new value to `object[place]`, while
To be consistent across the lisp and c code, I just want to point out that the definition of the c code should be:
void zap(*action, *selector, *object) { ... }
compared to
(mac zap (op place . args) ... )
But I also think what the c code really represents is an abstraction. You still need to write out the definitions of the functions each time you call zap. With the lisp code you write one line, which is the whole point of macros: write a single line of code which expands to several lines.
I think this highlights a weakness of Arc -- while terseness is probably wonderful once one has Arc in one's brain, it makes things considerably less legible to everyone else. Contrast with presenting CL/Scheme to proponents of the other, where I would assume they could mostly muddle through, Googling one or two odd things. Have you ever tried Googling "arc no function"? (Lisp analogy may not be accurate; substitute Python/Ruby or C#/Java if it makes you feel better.)
True, but in this case, the template serves a different purpose from the macro. It's there to make zap polymorphic, and would be unnecessary in a dynamic or type-inferred language. The main point is that pg's macro can be implemented as an ordinary function in a language that has references.
http://ycombinator.com/arc/arc3.tar
If you want a single, self-contained example, here's one:
How do you implement that in a language without macros?