Hmm... I confirm what I said. In a silly benchmark involving fibonacci, prime numbers and factorial (only real world examples as you can see ;), mzscheme took about 1mn35s and Arc (with fast numerical operations) only 58s. No doubt time is not broken as I used the Unix command this time. It also means that these 58s. include the 3s. on Arc startup. The actual time is closer to 55 s. No, if anyone has an idea about why a given code can be faster in Arc...
When I did the earlier Fibonacci benchmarking, I found it useful to take the code generated by ac, and run it inside mzscheme. (Note that :a will drop you from Arc to Scheme.) That is, running the exact same code that Arc does, just from the Scheme REPL. (This should take the same time as running in Arc, or else something is very wrong.) Then I could tweak the code a function at a time evolving from the Arc-generated code to the Scheme code, and see where the time was going.
Overall, it makes no sense that Arc would be faster. But it would be very interesting to find out why you're getting those results. Could there be some subtle algorithm difference, maybe lack of tail recursion, in the Scheme version?
Ok, I tried that. Running the fib code in a mzscheme REPL is slower than in an Arc REPL. But, if once in Arc REPL you type :a (and get to the mzscheme REPL with Arc functions loaded), the same Scheme code is then a little faster than the Arc counterpart. That means there is something in ac.scm that speeds up mzscheme computations. Maybe the fact that it's embedded in a module ? I really don't know, but at least this is not an aberration anymore.
I really don't know. It just is... It might be a bug in the time function, or for some reason the ugly code produced by the ac function gets optimized better than the simple mzscheme code...
Anyway, that's only a micro-benchmark. I'm trying to confirm this with more tests... I guess mzscheme will eventually be slightly faster than Arc.
For what it's worth, mzscheme's "hash-table-get" solves this by giving you an optional "default" value -- if you omit the value, then you get an exception; if you specify the value, then you just get that value -- unless the value is a procedure, in which case it calls that procedure. The procedure can raise your favorite exception, or perhaps _insert_ something into the hash table, or ... anything you want. This seems like a nice balance between simplicity and flexibility.