It looks like your confusion is about what zap does. zap is not a destructive variant of map; zap has no relation to map at all. What zap is is a generalized version of =. You often see expressions of the form (= foo (bar foo)), and zap abstracts them and add redundancy. When you write (zap func name), Arc will expand that into (= name (func name)). So in your first example, (zap [+ _ 10] x) turned into (= x ([+ _ 10] x)), which is the same as (= x (+ x 10)); x is the list '(1 2 3), and you can't add a number to a list, so you get an error. Cchooper's example, on the other hand, turns into (= x ([map [+ _ 10] _] x)), which is the same as (= x (map [+ _ 10] x)), which, as you can see, does what you want.
You are correct that it's readtables you want, but they are an mzscheme feature; unfortunately, there is no way (yet?) to use them in Arc. Using readtables, you can customize certain things, but I don't know that there's an easy way to do $(...) because of how they work (though I am by no means an expert). If you want to hack on ac.scm or brackets.scm to extend the readtables, the best resources I can recommend are the PLT Scheme language manual (the relevant chapter is here: http://download.plt-scheme.org/doc/mzscheme/mzscheme-Z-H-11....) and just Googling for it. (I didn't have very much luck when I tried, but go for it all the same!)
Also, note that intra-symbol syntax (a:b, a.b, a!b, ~a) is implemented separately in ac.scm, in the functions expand-ssyntax and expand-compose (though you also have to modify some predicates if you add things, e.g.ssyntax?). Again, this is not (yet?) available in Arc.
I do hope that ways to extend syntax will be available in Arc soon, but they aren't yet, and I couldn't figure out readtables well enough to generate a workable solution. Hopefully arc2.tar will include this. Good luck!
I think the logic is to make if a "primitive macro," the way + is a primitive function. Just as you can't define + in terms of Arc functions, you can't define if in terms of Arc macros. Nevertheless, (isa + 'fn), and so the thinking is that (isa if 'mac) makes sense.
There are valid reasons not to do things this way, of course. For instance, what's so powerful about macros is that they literally expand into a code tree, which (as you observed) if can't do. For that reason, why not have (isa if 'form) (or 'prim, or 'special, or something similarly descriptive)? Then you have first-class special forms without literally making them macros. This would be a big improvement over the current state of affairs:
arc> (type if)
Error: "reference to undefined identifier: _if"
.
arc> (let m (mc (x) `',x) (m 'not-a-declared-symbol))
(quote not-a-declared-symbol)
. However, here I'm not sure why. So after working through this, I'm not actually sure what these results signify. But here they are. Make of them what you will.
I'm fairly sure that "the code is the spec" applies to arc.arc, not to ac.scm. That is, anything that can interpret arc.arc properly is a conforming Arc implementation; ac.scm is just one of them. And since nil is (), then in Arc, your two lists are the same but with different formatting. Observe:
arc> (is nil '())
t
arc> (is nil ())
t
arc> (iso '(a b c) '(a . (b . (c . nil))))
t
arc> (iso '(a b c) '(a . (b . (c . ()))))
t
arc> (iso '(a . (b . (c . nil))) '(a . (b . (c . ()))))
t
Please note that the behavior of is is defined by ac.scm, not arc.arc. (And iso uses is to test for equality.)
The equality and interchangability of nil and () is just because there is a line in the definition of is that specifically says that false values are equal.
So even if you put #f in the terminating position, your lists will still be iso.
arc> (iso '(a b c) '(a b c . #f))
t
Are you saying that arc lists are #f terminated just because it doesn't break arc to put #f in random lists? Even if arc lists can be terminated by nil, (), and #f, it doesn't mean they necessarily are. Any given list (ignoring nested lists) can only have one termination object. I think it is reasonable to say that that list is terminated by that object. I do not think it is reasonable to say that list is terminated by another object, even if it could be, because the actual object at the end of the list is not that other object. And because the current implementation (the only official implementation) uses nil, I think it reasonable to say that arc lists are terminated by nil. Note the use of the present tense. If that changes at some future time, I my statement will obviously not apply.
In short, given the current implementation, we have (at least) six different ways to write nil: nil, 'nil, (), '(), #f, and '#f. These six things are all considered identical within Arc. The same is true, for instance, of 'a and (quote a), which are the same thing entered differently. You can check that they are the same with is; I won't put all those examples into this post.
I have never said that Arc lists aren't nil terminated--clearly, they are. What I'm saying is that Arc lists are nil terminated for any representation of nil--whether that representation is nil from Common Lisp, '() from Scheme, or #f from a leftover artifact of using the mzscheme reader.
Just because something is academic doesn't mean it's not worthwhile. For instance, map, keep, reduce, etc. are different if passed a function with side-effects. What happens if you give them a function which modifies the list as it's being traversed? A pathological example:
However, if map is passed a pure function, you can e.g. run one copy of the function on each core and run it in parallel.
And "dangerSet" is both non-Lispy and non-Arcy. It's non-Arcy because it's long. And it's non-Lispy because of that capital letter: danger-set would be marginally better. But nevertheless, pair? is shorter than is-pair, and (in my opinion) reads much more nicely.
They're different because they don't actually exist. Observe:
arc> def
#3(tagged mac #<procedure>)
arc> fn
Error: "reference to undefined identifier: _fn"
Since def is a macro, we can use it anywhere we like. But since fn is not, we can only use it in the head of a list, and it can't be overridden. fn, if, etc. should be first class: if not macros, then (type fn) should be 'prim or some such thing.
? (Though that requires the multi-argument [] form on the git "wiki"; you can of course do it as a normal fn, though.) I personally love map, reduce, keep, etc., and find them to be incredibly effective for working on lists.
However, I do quite like the idea of symbol macros. There's a nicety to .gramps that (.gramps) doesn't have. (Setting aside the fact that with the new . syntax, .gramps is an illegal name.)