Emacs, using the excellent arc.el and inferior-arc.el files in the REPL. Woo for in-editor REPLs and send-to-REPL commands. Not to mention automatic indentation.
For some reason, auto-indentation doesn't work for me. And also, I can't use the REPL unless I start emacs in the directory where arc is. Any advice would be appreciated.
Perhaps you could give example pieces of a .emacs files?
(autoload 'run-arc "inferior-arc" "Run an inferior Arc process, input and output via buffer *arc*." t)
(autoload 'arc-mode "arc" "Major mode for editing Arc." t)
(add-to-list 'auto-mode-alist '("\\.arc$" . arc-mode))
I also have arc.el and inferior-arc.el in my loadpath.
As for starting the REPL, inferior-arc.el assumes that there's an "arc" program in your path. I did this by adding a symlink pointing to my arc.sh, but you could also customize the arc-program-name variable.
And I'm on Windows so I can't use arc.sh :( ... I tried to make up for it by using arc-exe instead, but arc-exe won't load if it isn't in the same directory as ac.scm. (I think this is because the require-namespace isn't done at compile time like normal requires are.)
You should be able to set up a simple CMD script to start Arc on Windows. I think. I don't actually know that much about Windows. At the very least, you can set arc-program-name to be a manual invocation of MzScheme.
Oh, thats what you mean by auto-indenting. I was expecting it to act like lisp mode where it indents when I press enter (which would be nice to have if someone could manage it).
My problem so far is that when I try to load arc, because the current working directory is not the arc directory, even if it loads as.scm correctly, it can't load ac.scm or any *.arc files. I could set it up to load something like "mzscheme -mf C:\...\arc\as.scm" but I don't know how to make mzscheme look for other arc files in that directory as well.
The standard Emacs indentation behavior is to indent on TAB rather than newline. This is also the default for Lisp-mode, as far as I know. You can rebind this by setting RET to comment-indent-new-line, though.
You need to add some argument to mzscheme to get it to cd into the arc directory. Check the args passed in arc.sh.
Ok, thanks. I hacked a batch file and put it in my PATH so I can start arc from emacs. (Setting arc-program-name failed because run-arc wouldn't respect the quotes around the executable name.)
This is a cool idea, but I'm not sure that it's a good idea in general to add complexity to cons cells. Even if the interface is the same, the performance characteristics are different (that's the whole point, I suppose), and that makes reasoning about them more complicated.
Also, from a more wishy-washy perspective, it just feels right to me that the core data structure of Lisp has such an conceptually simple implementation. Two pointers: a car and a cdr. That's it
It seems to me that it's worth just making arrays available (which we'd have to do anyway, really) to keep lists as simple as possible.
Come now. It's always possible to "seamlessly" funge the division between lists and arrays. For the most part, they have virtually the same purpose: to keep a sequence of objects. One can imagine an implementation which keeps lists as arrays underneath, but if something really difficult to do in array - say insertion, or scdr - to switch over to singly-linked lists.
Really, though, I think what's missing in Arc is the layers of abstraction. We don't need two sequences - singly-linked lists and arrays. What we should have is the concept of a sequence. Iterating over a sequence, regardless of its implementation, should be handled by 'each, 'map, etc. I think as pg envisioned it, a profiler would eventually be integrated into Arc, which would measure the performance difference in using either of the implementations. If insertion is common in one place, and then indexed access in another, the compiler+profiler should be able to figure out that it should use linked lists in one place, then copy it over to the other place as an array to be used as indexed access.
Basically, what I'd like is a layer of abstraction - "this thing is a sequence, I'll choose array or linked-list later". Then, after profiling, I'll just add some tags and magically, this part of the code building the array uses linked-lists and that part doing weird indexed stuff (e.g. heap access) uses arrays.
When you look at it, most other dynamic languages don't have a separate linked-list type. They're all just "array", and not all of them use a sequential-cells-of-memory implementation of arrays. Say what you will about lesser languages, but first think - if everyone's doing it, there must be a reason. They could just be copying each other, of course, but one must always consider whether having two types of sequence, whose only true difference is their difference in access, is such an important thing.
I don't see lists in Lisp as just sequences. Rather, I don't see cons cells as just sequences. They're so much more versatile than that, which is part of what gives Lisp its power (cue "hundred operations on one data structure" quote). They can be used as maps, trees, etc. I think it would be a mistake to say, "these are mostly the same as arrays, let's implement them as arrays most of the time." Cons cells aren't the same as arrays.
I guess you're right in that arrays have more-or-less a subset of the functionality that cons cells do. Maybe it would be a good idea to have lists as the default and switch to arrays under some circumstances (lots of indexing or index-assignment?). But I'm skeptical about this as well.
Also, I foresee some unexpected behavior if the transition between conc cells and arrays is entirely behind-the-scenes. For example:
; Suppose foo is an array acting like a cons cell
(= bar (cons 'baz (cdr foo)))
(scdr (cdr bar) 'baz)
Now we'd need to somehow update the foo variable to point to a cons cell rather than array. You could imagine this getting even more tricky, even incurring large unexpected cost, with many variables pointing at different parts of an array-list and one of them suddenly scdr-ing.
All of that solved by the unrolled-list mockup. It works, and works with scdr, no matter how many pointers point in the middle of otherwise-proper lists, and even works with lists split by scdr, handling both the parts before and after the scdr-split seamlessly. Costs are also not very large - mostly the added cost is in the search through cdr-table for the next highest key. That said the added cost is O(n) where n is the number of individual cons cells scdr has been used on.
So yes, the above code you show will add cost. But how often is it used in actual coding anyway? The most common use of cons cells is straight sequences, and quite a bit of arcn can't handle improper lists (quasiquote comes to mind) - yet arc is useful enough to write news.yc.
Edit: Come to think of it, for the common case where scdr completely trashes the old cdr of a cons cell (i.e. no references to it are kept), the linear lookup through cdr-table will still end up being O(1), since keys are sorted, and the earlier cdr-table entry gets found first.
The post by raymyers (http://www.arclanguage.org/item?id=3997) gives some very cool examples of the power of bracket-style currying. In addition to cutting down the number of tokens in the common [foo bar _] case of bracket-notation, it allows much nicer wrapping of variadic functions - or just functions for which you want to leave more than one argument open. Compare [* 2] to (fn args (apply * 2 args)), for instance.
I'm very fond of the defcall functionality I added in Anarki - the ability to specify in-Arc the semantics for function calls on arbitrary types. So for example:
(defcall cons (l i)
(if (is i 0) (car l)
((cdr l) (- i 1))))
It would also work for arbitrary user-defined (via annotate) types as well, of course.