To me, one of the most fundamental features of Arc is taking the unification of code and data much further. I don't know of other Lisps that do this! K is another language that does.
arc> (= l '(1 2 3))
(1 2 3)
arc> (= f [+ _ 1])
#<fn: f>
arc> (map l '(0 1 2))
(1 2 3)
arc> (map f '(0 1 2))
(1 2 3)
No offense, but I found your example code really confusing.
For the benefit of people familiar with Common Lisp:
* (= ...) is assignment, not equality testing
* (map list index-list) is equivalent to (loop for index in index-list collecting (nth index list)), or in a more FP style (mapcar (rcurry #'nth list) index-list)
* (map function list) is equivalent to (mapcar function list)
I think your example would have been less confusing if it used larger numbers to highlight where addition was happening and where indexing was happening:
arc> (= l '(4 5 6))
(4 5 6)
arc> (= f [+ _ 10])
#<fn: f>
arc> (map l '(2 1 0 0))
(6 5 4 4)
arc> (map f '(0 1 2))
(10 11 12)
What is the logic here? Is l made into a function that holds state and returns each element in turn (like an iterator function)? Because I would've expected:
I don't like the Arc language because it's dynamically typed and thus inherently unsafe (see other threads for this sort of discussion.)
But I like this particular feature. If you think about it, an array is a mathematical function, or map, from indices to values. So it makes sense to be able to apply it to indices to get the respective values.
I think the list '(0 1 2) is behaving like the function — in CL syntax, sorry, I don't know Arc — (lambda (x) (elt '(0 1 2) x)). That is, the list is being treated as a sequence, which is a function from each index to the corresponding element.
This was discussed a lot before (according to Queinnec book at least) but people were worried that too much overloading would yield confusing code and bugs.
First public release of Arc came not long after Clojure.
Clojure is definitely better thought out as a language, and while Arc has some interesting ideas around web development, it also doesn't have a module system, so everything is just loaded into the same global namespace, which is pretty insane.
Keep in mind that Arc is the start of something with long-term goals; further, it's part of a lifecycle that didn't necessarily start with Arc but with the first Lisp. PG points to an early essay titled "The Hundred-Year Language" [1] as an indicator of where Arc is intended to go and some future outlooks that might inspire more evolution.
I don't know that any programming language can be everything it needs to be from the outset, but it certainly needs inherent featured supporting longevity, a framework that supports change and evolution, while still having a pleasing and useful function that can be taken advantage of immediately.
Ah, that makes sense. The next main difference in my mind is ergonomic, but relies on this regularity: functional syntax for composition, negation, quoted application. There are also other syntax additions and in my experience they're well-chosen and go a long way.
It would be more correct to say that they can be coerced to a function with a special purposes (e.g. using a set as a function is an alias for checking whether an item exists).
To say they are functions would be incorrect. By the same logic, a keyword is would be a function.
They're callable as functions, i.e. they implement clojure.lang.IFn. So unless you want to shave hairs on what it means to say they're not "functions", they _are_ functions. Sets, vecs, maps, keywords, and IIRC symbols are all IFn
Oh and (#{1 2} 3) is equivalent to (get #{1 2} 3) not (contains? #{1 2} 3)
I think that it depends upon what you interpret it when you say “it’s a function”; it’s data as well. Which, now that I reconsider it, was kind of the point that the parent was trying to make, that they’re also very much unified.