So, I worked a little more on the Psyco-like stuff I was writing for Arc. I wanted someting able to generate a new, optimized version of the code every time a function is called with a new set of arguments type. I dropped that, at least for now. The solution I implemented right now relies on a function (a special form actually) called compile. Its syntax is : (compile function-name return-type (arg-name type) (arg-name type) ... )
return-type is optional. It denotes the return type of the function, whatever its args are (thus it should only be given if the function always returns the same type).For each arg, you can do the same : specify its type, provided of course it never changes. Be careful here, there is no type checking or type inference at all... Let's see on our canonical example : the fib function. (time:fib 30)
-> time: 5417 msec.
-> 832040
(compile fib int (n int))
-><< (lambda (n) (if (not (ar-false? (ar-funcall2 __< n 2))) n (ar-funcall2 __+ (ar-funcall1 __fib (ar-funcall2 __- n 1)) (ar-funcall1 __fib (ar-funcall2 __- n 2)))))
-> >> (lambda (n) (if (not (ar-false? (< n 2))) n (+ (ar-funcall1 __fib (- n 1)) (ar-funcall1 __fib (- n 2)))))
(time:fib 30)
->time: 337 msec.
-> 832040
As you can see, 'compile lets you know what the old scheme code was, and what it is now. Fib (which is a good candidate for such optimisations) is then about 15 x faster.Only ac.scm was modified. TODO : - clean up the code - treat types other than numeric, - do some type inference, code elimination, etc., - compile to raw C code to even beat mzscheme and come close to CL perfs (Stalin or Ikarus are scheme too, and they run much faster), - find a way to deal with macros (the for mac is dead slow, for example) or inner anonymous functions (only named, top-level functions are taken into account yet). |