(defmacro defchunk [name tps] `(def ~name (quote ~tps))) (defmacro let-chunk [vname name val-vec & body] (let [chunk-def @(resolve name) types (map first chunk-def) part-names (map (comp symbol (partial str vname "!") second) chunk-def)] `(let [~vname ~val-vec ~@(interleave part-names (map #(list %1 (list vname %2)) types (iterate inc 0)))] ~...@body)))
user=> (defchunk foo [[int x][double y]]) #'user/foo user=> (let-chunk afoo foo [1 1.7] afoo) [1 1.7] user=> (let-chunk afoo foo [1 1.7] afoo!x) 1 user=> (let-chunk afoo foo [1 1.7] afoo!y) 1.7 Simple enough, and afoo!x and afoo!y are primitive. (defchunk complex [[double real][double imag]]) (defn cx-mult [w z] (let-chunk w complex w (let-chunk z complex z [(- (* w!real z!real) (* w!imag z!imag)) (+ (* w!imag z!real) (* w!real z!imag))]))) (after a few runs to get it all JITted) user=> (time (nth (iterate #(cx-mult % %) [0.0 1.0]) 10000)) "Elapsed time: 14.12232 msecs" [1.0 -0.0] Looks like one iteration taking less than 2 microseconds to me. And that's with iterate. Loop gives this: user=> (time (loop [c [0.0 1.0] n 10000] (if (= n 0) c (recur (cx-mult c c) (dec n))))) "Elapsed time: 2.54112 msecs" [1.0 -0.0] Interestingly, using definline to define cx-mult slows this down instead of speeding it up. Another macro could give you a super-defn that let-chunks certain function parameters, so the (let-chunk foo bar foo ...) stuff wrapping the body of cx-mult disappears into a macro. Yet another could give you a loop-chunk. For truly high performance, though, the vector boxing is a problem. JIT doesn't seem to be eliminating it, or the speed would be up to 1000x faster still. Defstruct/defrecord is probably what's needed here; this would mean a) modifying defchunk to emit a suitable defstruct/defrecord in addition to the type-partname pairs structure and b) making the other macros destructure these instead of vectors. But the above shows a working, if crude, first pass at implementing the facility under discussion in this thread. Replacing vectors with structmaps/records in it will probably produce a large speedup when the things are passed across function boundaries. The remaining bugbear will be that the let-chunk and loop-chunk will create a heap allocated structmap/record even if it's unused. Having the macros detect if it's unused might not be easy. I'm unsure, though, that heap allocation is as horrid as everyone here seems to be assuming it to be. It may be horribly slow in FORTRAN or even in C but modern JVMs make heap allocation very cheap. I wouldn't be surprised if using heap-allocated structmaps or records directly will do fine. There are also supposed to be more optimizations for primitive use, including passing across function boundaries, in the forthcoming Clojure 1.3. -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en