Care to explain it for the Lisp-impaired?
arc> (= flag t)
t
arc> (zap no flag)
nil
arc> flag
nil
arc> (= foo '(1 2 3 4 5))
(1 2 3 4 5)
arc> (zap (fn (x) (* x 10))
(foo 0))
10
arc> foo
(10 2 3 4 5)
BTW, in more idiomatic Arc you'd say (zap [* _ 10] foo.0)
Here's a line in HN that uses it: (zap [firstn votewindow* _] (uvar user votes))
This expands into roughly the equivalent of: (= ((profs* user) 'votes)
(firstn votewindow* ((profs* user) 'votes)))
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. void zap(void *object, void* (*selector)(void *), void (*action)(void*)) {
action(selector(object));
}
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].
Your first example would look like this:
int foo[5] = {1, 2, 3, 4, 5};
void *select_first(void *x) {return x;}
void act_times_10(void *x) {int *i = (int *)x; (*i)*=10;}
zap(foo, select_first, act_times_10);
Or am I missing something you didn't include in the description?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 object[place]=action(object[place])
has to do the lookup twice. 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. (zap [firstn votewindow* _] (uvar user votes))
In Python you wouldn't need a macro for this. You could just write del uvar(user, votes)[votewindow:]
or uvar(user, votes)[votewindow:] = []