It's not just implementation, but also semantics.
A vector is an ordered, O(1) access/modification, structure.
A hashtable is (usually) a non-ordered, amortized O(1) access/modification structure. The implementation details don't matter, but these characteristics do, since they are important to reason about your algorithms.
(Edit: You may think you can treat integer-indexed hashtables as vectors. Suppose you have a 'map->list' operation that applies fn to given aggregate type and returns the list of results. The semantics of (map->list fn a-list a-vector) is obvious. (map->list fn a-list a-hashtable) is not so obvious, and eventually you'll end up different map functions for different purpose. So it's a trade off---fewer data types and more specialized functions, or more data types and fewer
generic functions. Of course where is the optimal point is arguable.)
Can the compilers be smart enough to figure out the data structure that minimize your algorithm's computation complexity? I don't know. Eventually, maybe, but at that time algorithms will be described in very abstract level, I guess.
Of course you can merge these two characteristics (adding order info to hashtables, which I believe Ruby just did recently). It's a trade off, affecting constant factor.
But one of the sources of the strength of Erlang's model is inherently built-in the language---many things are passed by value, including aggregate types, so that GC can run per-thread and you don't need to care about synchronization. You can implement the same model on top of other languages (e.g. see Termite http://lambda-the-ultimate.org/node/841 ), but you do change the language's semantics.
I incorporated regexp literal in Gauche Scheme and found it very handy. Regexp literal is written as #/pattern/. When appears in the procedure position it also works as a matcher.
(#/\d+/ "abc123") => #<match object>
The matcher returns a match object if the given string matches the pattern; you can extract submatches from it. The match object also works like a procedure.
The good thing I found about this "acts like a procedure" feature is that I can pass around it wherever a procedure is expected. For example, grep can be expressed in terms of the standard 'filter' procedure.
(filter #/\w+/ list-of-strings)
(I'm not sure Arc can go this direction, since Arc's operators that takes predicates (e.g. 'find', 'some', 'all', ...) does "auto-testification"---if a given object isn't a procedure, it creates a predicate that tests equality to the given object---which may conflict with this type of extended use of "callable objects".)
The difficult part is, of course, to test if the choice of axioms is optimal you have to build number of different real applications on top of it, and real applications need vast libraries.
Something which seems so harmless as 'standard input port' needs to be reconsidered if you start supporting large character set. Another example is the history of the quest to find the right way to do asynchronous inter-process communication---the flaw of the core model only surfaces when some applications try to push the envelope.
News.YC is a real application and I wouldn't call its libraries vast. I suspect it would be enough to do 4 or 5 fairly different types of applications, maybe a couple thousand lines each.
I'd love to do a graphics application next, preferably web-based. Anyone have opinions about the right structure for such a thing?
I don't deny that News.YC is a real application. OTOH, I've used my Scheme implementation for several commercial projects and I don't think I can port them to the current version of Arc straightforward. So I try to pinpoint the reasons. Libraries can come afterwards, so here I think of the core features.
A couple of things I think indispensable are the ability to write non-consing inner loop and O(1) access structure (vectors)---combining these with macros I can make the speed-critical routine run pretty fast. Although this seems an optimization issue, it is so critical to the extent that, if I weren't have them I couldn't have used Scheme to the projects.
Managing concurrent processes and threads safely and efficiently is another part that the language can help tremendously if it provides a right model. Arc's current choice of atomic-invoke is simple and clean, but questionable in terms of scalability; at least I cannot use that model in my app. (And that model is so fundamental that it'll be pain to change later to go through all atlets and atwiths to replace them for the different primitives.)
Oh BTW, I think the primitive 'dead' in ac.scm line 1083 is missing wrapnil.
The source itself is pretty close to ActionScript compatible. Problem is, I mess with the __proto__ property a lot for basic data types and for scope chaining. It's what lets me use JavaScript's native lookup mechanism for variable lookup; instead of searching down an a-list, I make each activation frame a JavaScript object and knit their prototypes together, so I can lookup variables with 'env[symbol]' and the whole search process is in C. __proto__ is a non-standard property; it's supported in all major browsers, but I wouldn't bet on it appearing in Flash. And I'm not sure it'd be fast enough if you had to implement variable lookup in the interpreter itself.
I thought about writing a compiler instead of an interpreter, but macros & quasiquote present a bit of a problem. You can compile the code down to JavaScript...but if you run into a quasiquote, you've got to jump back into the compiler to evaluate it, then splice that code back into your function, then eval the newly-generated JavaScript code to get back a real function. Remember, even ordinary functions like setforms (in the standard library) call macex at runtime, so you can't just separate things into a compile-time-only macroexpansion pass. And ActionScript doesn't have an eval function, so that gets a little complicated.
I understand your point about macros but not quasiquote... I thought `(a b ,x ,y c d) was an abbreviation for (list 'a 'b x y 'c 'd)? What am I missing?
I wonder if it might work if you have an identical Arc implementation in your compiler and in your runtime so that all the macro expansions can be done at compile time.
ActionScript3 flash.display.Loader.load() says it loads SWF files... does this include compiled ActionScript? If so, maybe a REPL inside the Flash application could be written by calling back to your server which ran the compiler. Not ideal, but certainly more fun than an edit -> compile -> run -> debug cycle.
`(a b ,x ,y c d) is an abbreviation for (quasiquote (a b (unquote x) (unquote y) c d). The quasiquote returns a literal list, except that whenever it encounters an unquote or unquote-splicing it hops back into the evaluator and evaluates the form in the local environment.
Flash load() is probably your best bet. My startup has a similar problem - dynamically generating code that will run in a browser - and we eventually decided it was easier to go with JavaScript/eval than Flash, even though we have to support Flash anyway for the finished product. Our other option was to send the code back to the server through Flash's XMLConnection, compile it there, returns a URL of the compiled SWF through the connection, then loadSWF() it and hope we can figure out how to dynamically reference the new classes. Check out MTASC for the server; Macromedia's Flash Compiler won't run on the command line.
Or you could just punt on the dynamic features. I don't support continuations in ArcLite, and I know someone doing a native-code port that's planning to leave out a few of the more dynamic features. Beware that I found (= ...) doesn't work if you leave out (macex ...), though.
Yeah, it was a deliberate design decision by Macromedia. They wanted to keep the VM small, so they deliberately left out anything that smacked of a runtime compiler. Eval, regexps. Though I heard regexps may have come back in AS3...
I haven't yet heard of any Scheme -> JavaScript compilers that support eval (and thus a REPL)... so ArcLite (or some other interpreter written in JavaScript) would be a good way to support interactive programming in the meantime.
Not sure about the structure being right or not, but the script interface to The Gimp comes to mind, at least for graphics primitives, only because it is Lisp and could be translated to Arc w/o reinventing the wheel (reinvention could be Phase II:-)).
I'm not sure what you have in mind with graphics app, but I think a wiki whose pages could contain some kind of simple, "object-oriented" vector graphics (e.g. using a small Flash app) would be cool.
SVG still needs a plugin in many of the popular browsers. If you want something that'll work out of the box, I'd use Canvas (or excanvas.js for IE compatibility). SVG's a better technology, but the winner tends to be the one that works now, not the one that will work better eventually.
One idea I'm mulling for some time is that, when you compile a function you mark it with the macros you've used, and when one of the macros is redefined it triggers recompilation of the original function. You can delay the recompilation until the function is called next time, of course.
(Actually it's not only for macros, but it will work well for inlining built-in functions.)
Possible drawback is that the effect of macro redefinition isn't very obvious in such a system. You change a macro in running server, and it can trigger recompilation of large potion of the code...
Interesting idea. However, for that to work, one would need to recompile (or mark as dirty) _anything_ that referenced the macro, which could be lists or even a single variable who's value is simply a symbol.
i.e.
(mac foo () ''a)
(= bar (foo))
And if a macro expansion used the value of bar, i.e.
(mac baz () `(prn ',bar))
then anying using baz also would need to be recompiled.
I don't think so. Since Arc (and most Lisp dialects) are applicative order, (foo) is evaluated once when (= bar (foo)) is evaluated. Redefining foo won't affect the value of bar (and it doesn't matter whether foo is a macro or a function).
Of course, if (= bar (foo)) is a part of a function, then the function should be recompiled.
Why?
No matter whether foo is a macro or a function, a closed value of 'x' is fixed in the closure returnd by bar, so redefining foo shouldn't affect the closure bound to x. (But the next call of bar returns a closure that closes 2 as 'x'). Am I missing something?
Like I said -- the usual solution, which you think about, is to lower your expectations. And I'm not joking when I say that: you really just decide to expect that `x' is not going to changed since it's "closed", so you're happy with the result. Some people set their expectations lower, and they expect a macro redefinition to not change anything about existing bindings, so they won't think about your hack as necessary.
And BTW, this is not just some cooked up academic non-problem. It's a practical issue. Consider this example:
If that macro change will (with your suggestion) lead to recompiling `bar', but that will not affect the current active call. This is a very common problem with hacking live servers (as pg often talk about):
* You cannot change the main server handler loop unless you make it call itself via its name, so the recursive call will use the new definition.
* Even if you do, you should still be extremely careful since you might change the code when there's a live thread around which was compiled with the old macros, and might rely on the old macros. For example, `f1' and `f2' use `foo', `f1' is invoked in a thread, now `foo' gets redefined, after that's done `f1' continues to call `f2': old code is calling new one, things break.
I still believe you are talking different things. My "expectation" is derived from these axioms:
* Macro is a local source-code transformation that replaces macro call with the macro definition (with some hygienic magic, if you prefer).
* The language adopts applicative order.
If you want redefining foo to affect the value of the closed variable 'x', then either you have a non-trivial definition of macros (macro transformation requires transformation of code surrounding the macro call) or you are adopting different evaluation semantics (like x is bound by call-by-name).
Note that your problem occurs even foo is a procedure. It's not a macro problem. It's a problem of semantics of closed variables.
(cut + 1 <>) is (lambda (x) (+ 1 x))
(cut + <> <>) is (lambda (x y) (+ x y))
The possibility of allowing changing argument orders by numbering them were discussed, but eventually dropped, since you can always fall back to lambda (arc's fn). So making it general would just increase complexity without gaining much more expressive power. At least that was the consensus there. (Of course you can argue otherwise)
It might be a bit clumsy for a reference. I'm more interested in the relationship between arg primitives and other Scheme's primitives, to see how pg made design choices differently.