Re: Parameter ordering on map/reduce
Hi Nathan, There is actually a simple answer to your question. map can take a fuction of multiple parameters along with multiple collections. i.e. (defn f [x y] (+ x y)) (map f [1 2] [3 4]) = (4 6) (Warning I did this computation in the Clojure instance in my head, so some details may be slightly off.) Paul On 3/31/09, Nathan Sorenson n...@sfu.ca wrote: First of all, I would like to thank Rich and this community for producing such a pleasurable language, and for putting up with with all the unpleasant nit-picking of new users. That being said... I am curious as to why the function parameter is specified before the collection parameter in map/reduce. I have never used a lisp before, and may not be aware of idiomatic style, but it seems to be the convention elsewhere in Clojure (assoc, conj, .method calls, etc...) to have the altered data structure be the first parameter. Would this not allow mixing map into a threaded expression: (- [1 2 3] (map inc) (assoc 0 4) (reduce +) (conj :anotherthing)) Perhaps this style is rare in practice? Certainly it is easy enough to write a custom map/reduce which acts this way, so I suppose my question is mostly philosophical. --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: Clojure Users Group - Denmark
I would certainly be interested. Lau are you out there ? /mac On Mar 30, 9:35 pm, Krukow karl.kru...@gmail.com wrote: On Mar 30, 3:40 pm, Christian Vest Hansen karmazi...@gmail.com wrote: Great. Now we are at least 3 danes who know Clojure - I have a feeling that there is at least one other guy out there :) We have to start somewhere ;-) Perhaps I'll arrange a 'geek night' at my company to talk about the language - that might give a few more users! I live in Copenhagen, but i think we're a tad too few to form city local groups. Maybe if the scope was broadened to be more like lambda lounge? That might be an option... Anyway, go subscribe to the feed. If you plan on arranging any meetings or talks about Clojure in Copenhagen then let me know, I'll put an announcement on the site. /Karl --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Parameter ordering on map/reduce
First of all, I would like to thank Rich and this community for producing such a pleasurable language, and for putting up with with all the unpleasant nit-picking of new users. That being said... I am curious as to why the function parameter is specified before the collection parameter in map/reduce. I have never used a lisp before, and may not be aware of idiomatic style, but it seems to be the convention elsewhere in Clojure (assoc, conj, .method calls, etc...) to have the altered data structure be the first parameter. Would this not allow mixing map into a threaded expression: (- [1 2 3] (map inc) (assoc 0 4) (reduce +) (conj :anotherthing)) Perhaps this style is rare in practice? Certainly it is easy enough to write a custom map/reduce which acts this way, so I suppose my question is mostly philosophical. --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: Parameter ordering on map/reduce
If I remember correctly (I wasn't able to find the thread where this same subject was explained), one must make a difference between functions intended to work on data structures, and functions intended to work on sequences. Data structures are not volatile as sequences are, and those functions that manipulate them generally take the data structure (vector, map, set, etc.) as their first argument. It makes sense to create a partial function with the data structure captured by the partial call. Sequences are volatile, and thus less subject to be captured by a partial call. And to enforce the difference between the 2, sequences are generally the 2d or last argument to such functions. HTH, -- Laurent 2009/3/31 Nathan Sorenson n...@sfu.ca First of all, I would like to thank Rich and this community for producing such a pleasurable language, and for putting up with with all the unpleasant nit-picking of new users. That being said... I am curious as to why the function parameter is specified before the collection parameter in map/reduce. I have never used a lisp before, and may not be aware of idiomatic style, but it seems to be the convention elsewhere in Clojure (assoc, conj, .method calls, etc...) to have the altered data structure be the first parameter. Would this not allow mixing map into a threaded expression: (- [1 2 3] (map inc) (assoc 0 4) (reduce +) (conj :anotherthing)) Perhaps this style is rare in practice? Certainly it is easy enough to write a custom map/reduce which acts this way, so I suppose my question is mostly philosophical. --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: Parameter ordering on map/reduce
Hi Nathan, On 31 Mrz., 09:40, Nathan Sorenson n...@sfu.ca wrote: First of all, I would like to thank Rich and this community for producing such a pleasurable language, and for putting up with with all the unpleasant nit-picking of new users. That being said... I am curious as to why the function parameter is specified before the collection parameter in map/reduce. I have never used a lisp before, and may not be aware of idiomatic style, but it seems to be the convention elsewhere in Clojure (assoc, conj, .method calls, etc...) to have the altered data structure be the first parameter. I believe this is to allow more than one sequence in map expressions: (map - '(1 2 3) '(3 2 1)) = (-2 0 2) and for reduce, it takes another optional arg to start the reduce with: (reduce conj [1 2] '(a b)) = [1 2 a b] Would this not allow mixing map into a threaded expression: (- [1 2 3] (map inc) (assoc 0 4) (reduce +) (conj :anotherthing)) Perhaps this style is rare in practice? Certainly it is easy enough to write a custom map/reduce which acts this way, so I suppose my question is mostly philosophical. there was a thread devoted to a macro to express this kind of piping, http://groups.google.com/group/clojure/browse_thread/thread/66ff0b89229be894/e78c3585589cdbf6?lnk=gstq=pipe#e78c3585589cdbf6 (defmacro pipe Threads the expr through the forms. Inserts x as the last item in the first form, making a list of it if it is not a list already. If there are more forms, inserts the first form as the last item in second form, etc. ([x form] (if (seq? form) `(~(first form) ~@(rest form) ~x) (list form x))) ([x form more] `(pipe (pipe ~x ~form) ~...@more))) which is the same as the - except it threads its first arg to the last position of each form instead of the second (pipe x (f a b)) = (f a b x) Using this macro is IMO good for expressing long chains of filtering, mapping and reducing, its more readable, less nested and easier to edit than the equivalent nested expression. I have some code which is using this macro, but most of the time I just don't need such long pipes or I'm using a let to create named intermediate results for debugging and sanity. In the above mentioned thread, there is also a more general let- macro which would make your example work without any modifications to the core functions: (let- x [1 2 3] (map inc x) (into [] x) (assoc x 0 4) (reduce + x) (list x) (conj x :anotherthing)) = (:anotherthing 11) erik --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: Parameter ordering on map/reduce
Would this not allow mixing map into a threaded expression: You might also be interested in this thread: http://groups.google.com/group/clojure/browse_thread/thread/66ff0b89229be894 Where various people created a let- (or pipe) macro for such a purpose. --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Thread-local bindings per agent
Hi all! Here's a set of macros I have found useful for creating simulated thread-local bindings for specific agents: (defmacro bind-agent Adds bindings to an agent's metadata [#^clojure.lang.Agent a bindings] (list 'let (vector 'ba# a) (list 'do (list 'alter-meta! 'ba# 'assoc :agent-bindings (list 'quote bindings)) 'ba#))) (defmacro send-bound Send to an agent with metadata bindings [#^clojure.lang.Agent a fun] (list 'send a (list 'fn [' 'x#] (list 'binding (- a qualify-sym find-var var-get meta :agent-bindings) (list 'apply fun 'x#) Where qualify-sym is a private function in clojure.contrib.error-kit which was referred to me by the helpful chaps in #clojure, and attributed to Chouser. Example: user (def z 1) #'user/z user (def x (bind-agent (agent 1) [z 2])) #'user/x user (+ @x z) 2 user (send-bound x #(+ % z)) #ag...@19c205b: 3 user @x 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 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 -~--~~~~--~~--~--~---
Re: oo
On Mar 29, 8:08 am, Meikel Brandmeyer m...@kotka.de wrote: Hi, Am 27.03.2009 um 09:25 schrieb Mark Engelberg: I may come along and want to extend test-prefer to a type ::d which derives from ::c and ::e, where ::e provides an alternative implementation. ab (a and b are intended to be hidden from end-user) | | -- | c e | | | d (derive ::d ::c) (derive ::d ::e) (defmethod test-prefer ::e [h] e) Now, as an external user, I know nothing about where test-prefer on ::c gets its behavior. Obviously, I have to disambiguate between whether test-prefer chooses ::c over ::e, so I may try something like this: (prefer-method test-prefer ::c ::e) But this will not work. I still get an error saying I need to disambiguate between ::a and ::e. And not knowing anything about ::a, I could be very confused, and not know how to provide this information. Is there some special reason, why choosing ::c is not enough in prefer-method? As soon as I preferred ::c over ::e. Why should I then need to go further up the tree? No, this was just a conservative decision on my part, but prefer- method could prefer the path through ::c and not just ::c and its descendants. I'm working on supporting this now. Rich --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: I need help tracking down a performance problem.
For those interested, I managed to improve the performance of my original program from 2 minutes 40 seconds to decode 1000+ files down to 2 minutes. I'm still far from my goal, but it's an improvement, especially since the code is shorter and (IMO) cleaner. You can see it here: http://bitbucket.org/gnuvince/clj-starcraft/src/tip/src/starcraft/replay/parse.clj And here's another question, running the program with -Xprof shows that nearly 20% of my execution time is spent calling java.lang.reflect.Array.set. Is there something wrong with the way I type hint my array in make-reader? Thanks, Vincent. On Mar 19, 8:12 pm, Vincent Foley vfo...@gmail.com wrote: Hello, For the past few days, I've been trying, unsuccessfully, to make an application I wrote faster. A Java program that performs, more or less, the same task takes 12 seconds (on my machine) to parse 1000 files; my Clojure program takes nearly 3 minutes. This more than an order of magnitude slower! Using the profiling tools available with the JVM, I quickly determined which function was the costliest. I copied it into a simple script file to profile it in isolation. I have made the script and the profile results (long!) available at this URL:http://gist.github.com/82136 I'm finding the results puzzling: is dereferencing a var *that* expensive? Can anyone tell me if they see something fundamentally wrong with my approach that would explain this abysmal performance? Thank you, Vincent. P.S.: I am using Sun's JVM 1.6.0_10 as shipped in Ubuntu Ibex. My machine is an Athlon 64 X2 4200+ with 3 GB of RAM. --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: Clojure Users Group - Denmark
On Mar 31, 1:00 pm, martin_clausen martin.clau...@gmail.com wrote: I would certainly be interested. Lau are you out there ? So far one user in Cph, one in Aarhus. Where are you from? And how about Lau? If you are able to attend the JAOO 2009 conference in Aarhus, I'll arrange a dcug meeting. I believe that Rich is coming to speak about Clojure at JAOO, and I suspect we could talk him into joining for the dcug meetup ;-) That would be a nice kick-off for dcug. Please let me know if JAOO is an option for you! -- Karl --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: I need help tracking down a performance problem.
Did you try using aset-int instead of aset? On Tue, Mar 31, 2009 at 8:25 AM, Vincent Foley vfo...@gmail.com wrote: For those interested, I managed to improve the performance of my original program from 2 minutes 40 seconds to decode 1000+ files down to 2 minutes. I'm still far from my goal, but it's an improvement, especially since the code is shorter and (IMO) cleaner. You can see it here: http://bitbucket.org/gnuvince/clj-starcraft/src/tip/src/starcraft/replay/parse.clj And here's another question, running the program with -Xprof shows that nearly 20% of my execution time is spent calling java.lang.reflect.Array.set. Is there something wrong with the way I type hint my array in make-reader? Thanks, Vincent. On Mar 19, 8:12 pm, Vincent Foley vfo...@gmail.com wrote: Hello, For the past few days, I've been trying, unsuccessfully, to make an application I wrote faster. A Java program that performs, more or less, the same task takes 12 seconds (on my machine) to parse 1000 files; my Clojure program takes nearly 3 minutes. This more than an order of magnitude slower! Using the profiling tools available with the JVM, I quickly determined which function was the costliest. I copied it into a simple script file to profile it in isolation. I have made the script and the profile results (long!) available at this URL:http://gist.github.com/82136 I'm finding the results puzzling: is dereferencing a var *that* expensive? Can anyone tell me if they see something fundamentally wrong with my approach that would explain this abysmal performance? Thank you, Vincent. P.S.: I am using Sun's JVM 1.6.0_10 as shipped in Ubuntu Ibex. My machine is an Athlon 64 X2 4200+ with 3 GB of RAM. --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: I need help tracking down a performance problem.
No, but in my defense I did not know such a function existed :) I'll give it a whirl and report back! On Mar 31, 9:57 am, David Nolen dnolen.li...@gmail.com wrote: Did you try using aset-int instead of aset? On Tue, Mar 31, 2009 at 8:25 AM, Vincent Foley vfo...@gmail.com wrote: For those interested, I managed to improve the performance of my original program from 2 minutes 40 seconds to decode 1000+ files down to 2 minutes. I'm still far from my goal, but it's an improvement, especially since the code is shorter and (IMO) cleaner. You can see it here: http://bitbucket.org/gnuvince/clj-starcraft/src/tip/src/starcraft/rep... And here's another question, running the program with -Xprof shows that nearly 20% of my execution time is spent calling java.lang.reflect.Array.set. Is there something wrong with the way I type hint my array in make-reader? Thanks, Vincent. On Mar 19, 8:12 pm, Vincent Foley vfo...@gmail.com wrote: Hello, For the past few days, I've been trying, unsuccessfully, to make an application I wrote faster. A Java program that performs, more or less, the same task takes 12 seconds (on my machine) to parse 1000 files; my Clojure program takes nearly 3 minutes. This more than an order of magnitude slower! Using the profiling tools available with the JVM, I quickly determined which function was the costliest. I copied it into a simple script file to profile it in isolation. I have made the script and the profile results (long!) available at this URL:http://gist.github.com/82136 I'm finding the results puzzling: is dereferencing a var *that* expensive? Can anyone tell me if they see something fundamentally wrong with my approach that would explain this abysmal performance? Thank you, Vincent. P.S.: I am using Sun's JVM 1.6.0_10 as shipped in Ubuntu Ibex. My machine is an Athlon 64 X2 4200+ with 3 GB of RAM. --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: Please suggest a way to learn just enough Java for Clojure
+1 to Stuart's answer. Clojure is very tightly integrated with Java. And knowing Java well helps a great deal. Personally I like learning from a more formal, comprehensive, book rather than from spread-out individual tutorials. It gives you the advantage of learning the workflow, and approaches in Java, which is hard to pick up from tutorials. I would recommend that you pick up a book and read through it from start to finish. Since you already have so much programming background, it shouldn't take much time either. --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: Possible Solution for Left-Right Precedence and More when using Multimethods? (was re: oo)
On Mar 31, 2009, at 16:32, Rich Hickey wrote: Here are some problems/limitations of existing OO/GF systems that I don't intend to repeat: ... I agree that these are not desirable features. I have had to work around some of them many times in the past. Traditional OO combines aspects that should better be handled separately. Here are the areas I'm looking to improve: - There's no easy way to talk about the method you would get if you were dispatch value X. Note that this is not the same as call-next- method, which reintroduces global ordering requirements, but allows for easy explicit reuse of already-defined methods. That would be VERY nice to have. More than once I ended up writing a private function that I then called from several methods in the same multimethod, to avoid code duplication. - Currently, a preference doesn't encompass the path through the preferred value to its ancestors, but could. - If you have a set of common preferences, there's no easy way to create them in advance and share them among methods. There are issues here related to ensuring preference consistency and caching. At the moment, a multimethod takes two dispatch-oriented parameters: a hierarchy and a dispatch function that returns a single item from the hierarchy. How about generalizing the dispatch function in two ways: - it can return a sequence of items that will be tried in order - it can access the hierarchy Accessing the hierarchy is a minor point since this is already possible (write a dispatch function that uses parents, ancestors, etc.; for a hierarchy other than the global one, make the dispatch function a closure that refers to the hierarchy). Maybe it could be made more convenient. Returning a sequence should be sufficient to let the dispatch function handle any kind of preference. prefer-method could thus go away. Instead, there would be a set of utility functions to facilitate writing dispatch functions for common cases. A single dispatch function could be used for any number of multimethods. I think this should be sufficient to cover all cases you mentioned, but of course it needs to be tried in practice. Konrad. --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: Possible Solution for Left-Right Precedence and More when using Multimethods? (was re: oo)
On Tue, Mar 31, 2009 at 9:45 AM, Konrad Hinsen konrad.hin...@laposte.net wrote: I think this should be sufficient to cover all cases you mentioned, but of course it needs to be tried in practice. I think your idea of specifying a sequence of items to try in the dispatching function, at the point of definition for the multimethod, violates the principle of allowing library consumers to easily extend this on their own without having to contact the library designer. --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: Clojure Users Group - Denmark
I am in Copenhagen. JAOO is definitely a possibility. /mac On Mar 31, 2:26 pm, Krukow karl.kru...@gmail.com wrote: On Mar 31, 1:00 pm, martin_clausen martin.clau...@gmail.com wrote: I would certainly be interested. Lau are you out there ? So far one user in Cph, one in Aarhus. Where are you from? And how about Lau? If you are able to attend the JAOO 2009 conference in Aarhus, I'll arrange a dcug meeting. I believe that Rich is coming to speak about Clojure at JAOO, and I suspect we could talk him into joining for the dcug meetup ;-) That would be a nice kick-off for dcug. Please let me know if JAOO is an option for you! -- Karl --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: Thread-local bindings per agent
Hi Andrew, Am 31.03.2009 um 04:53 schrieb Andrew Stein: Here's a set of macros I have found useful for creating simulated thread-local bindings for specific agents: Please allow me to give you some feedback concerning the style of your macros. - (list 'let ), (vector 'ba# a), This is most likely not what you want. 'foo will expand exactly to the symbol foo, ie. it will capture the binding of foo in the context where the macro is expanded. This is bad and should generally be avoided. There are exceptions, eg. this in proxy, but they should only be used rarely and their use should clearly documented. `foo on the other hand will expand to the foo known to your macro and hence always work as expected without clashing with the code that actually uses the macro. - 'ba# is a good idea to generate a variable in the macro expansion which is almost surely not used by the code calling the macro. However this only works with `ba#. 'ba# is just the symbol ba#, which is not protected against capture. Additionally the # notation only works inside a ` form. So when you write (list `ba# `ba#) the second will be different from the first. - This leads to the general form. Instead of building the data-structures manually simply use syntax-quote. Compare the two forms: (list `foo x) vs. `(foo ~x). I find the second much clearer. It allows to read the macro almost like the final expansion. - The #^clojure.lang.Agent tag is actually not correct. The parameter to the macro is not an agent. It is a form! Maybe just a symbol (nameing a Var at runtime) or a form like (agent 1), that is a list consisting of the symbol agent and the number 1. The macro is expanded at compile time, while the agent is only created at runtime. So the macro actually never sees the agent itself. Don't forget: the macro is a function acting on code! Not on runtime values! (Disclaimer: Henceforth everything is untested.) (defmacro bind-agent Adds bindings to an agent's metadata [#^clojure.lang.Agent a bindings] (list 'let (vector 'ba# a) (list 'do (list 'alter-meta! 'ba# 'assoc :agent-bindings (list 'quote bindings)) 'ba#))) I would write this as follows. (Note, I'm not sure how you exactly use your code, but I would capture the vars immediately.) (defmacro bind-agent [a bindings] (let [bindings (mapcat (fn [[the-var the-val]] [`(var ~the-var) the-val]) (partition 2 bindings))] `(let [bound-agent# a] (alter-meta! bound-agent# assoc :agent-bindings (hash-map ~...@bindings) (defmacro send-bound Send to an agent with metadata bindings [#^clojure.lang.Agent a fun] (list 'send a (list 'fn [' 'x#] (list 'binding (- a qualify-sym find-var var-get meta :agent-bindings) (list 'apply fun 'x#) Now it gets a bit ugly. In your version as well as in mine. In yours we have to jump through hoops to retrieve the Var where the agent is stored. But the limits the usefulness to such agents. Agents stored in locals, refs or atoms fall under the table. In my version we have to re-invent binding. I really miss binding* which acts like binding but is a function and takes a map and a thunk. (defn send-bound [a f args] (if-let [bindings (:agent-bindings (meta a))] (send a #(try (clojure.lang.Var/pushThreadBindings bindings) (apply f % args) (finally (clojure.lang.Var/popThreadBindings) (apply send a f args)) Please note, what we got from resolving the vars immediately when a bound agent is created: - send-bound is not a macro anymore. (- That's a Good Thing) - send-bound now works on any agent. Not only agents stored in Vars. - The #^clojure.lang.Agent tag would now make sense, allthough it's not necessary. Phew. Long answer. I hope it helps, though. Sincerely Meikel smime.p7s Description: S/MIME cryptographic signature
Re: Thread-local bindings per agent
Hi again, Am 31.03.2009 um 19:04 schrieb Meikel Brandmeyer: (Disclaimer: Henceforth everything is untested.) I knew, why I put that there Here some hopefully more functional version: (defmacro bind-agent [a bindings] (let [bindings (mapcat (fn [[the-var the-val]] [`(var ~the-var) the-val]) (partition 2 bindings))] `(let [bound-agent# ~a] (alter-meta! bound-agent# assoc :agent-bindings (hash-map ~...@bindings) Note the ~ in front of the a in the let - send-bound is not a macro anymore. (- That's a Good Thing) Maybe I should also give some more rationale, why this is a Good Thing. send-bound depends on runtime information: the metadata of the agent. (Actually the binding is the problem.) This is a sign, that using a macro is not a good idea. The macro happens at compile time. So it can't really use this information, since the agent doesn't exist, yet. Only in special cases with Vars. But even then one can do things like this, I would expect not to work: (do (def a (bind-agent (agent 1) [z 2])) (send-bound a some-fun)) One can try to push the limits with tricks and eval, but this will lead to fragile, contorted code, which almost surely will come back to haunt you So use macros wisely, but prefer functions were ever possible. Sincerely Meikel smime.p7s Description: S/MIME cryptographic signature
Re: I need help tracking down a performance problem.
I'm sorry if I missed you mentioning it, but have you tried running your code with (set! *warn-on-reflection* true) in effect? -- Aaron --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: I need help tracking down a performance problem.
On Tue, Mar 31, 2009 at 1:24 PM, Aaron Cohen remled...@gmail.com wrote: I'm sorry if I missed you mentioning it, but have you tried running your code with (set! *warn-on-reflection* true) in effect? Ugh, I should have looked at your code before I sent that. There it is on line 1. ;) -- Aaron --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: Thread-local bindings per agent
Hi the third try... (defmacro bind-agent [a bindings] (let [bindings (mapcat (fn [[the-var the-val]] [`(var ~the-var) the-val]) (partition 2 bindings))] `(let [bound-agent# ~a] (alter-meta! bound-agent# assoc :agent-bindings (hash-map ~...@bindings)) bound-agent#))) and of course it should return the agent.. Sincerely Meikel smime.p7s Description: S/MIME cryptographic signature
Re: Gen-class, extending a parameterized type
As an interim solution, you could write a wrapper class in Java that extends the parameterized class, then extend that class in Clojure. -Stuart On Mar 31, 11:23 am, Chas Emerick cemer...@snowtide.com wrote: gen-class does not yet support parameterized types. Rich is aware of the issue, though, and I suspect he'll wend his way around to it sooner rather than later. Depending on timing, I might try my hand at a patch that implements this. - Chas On Mar 30, 2009, at 2:27 PM, Greg Harman wrote: I need to extend an abstract Java class with a generic type, ala: public abstract class FooT {} I tried the syntax (gen-class :name fooImpl :extends com.x.FooT) and get java.lang.ClassNotFoundException: com.x.FooT Without the T I'd get: a RuntimeException complaining that I'm extending the raw type instead of the parameterized type. Any suggestions? thanks, Greg --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: Possible Solution for Left-Right Precedence and More when using Multimethods? (was re: oo)
On Mar 31, 11:45 am, Konrad Hinsen konrad.hin...@laposte.net wrote: On Mar 31, 2009, at 16:32, Rich Hickey wrote: Here are some problems/limitations of existing OO/GF systems that I don't intend to repeat: ... I agree that these are not desirable features. I have had to work around some of them many times in the past. Traditional OO combines aspects that should better be handled separately. Here are the areas I'm looking to improve: - There's no easy way to talk about the method you would get if you were dispatch value X. Note that this is not the same as call-next- method, which reintroduces global ordering requirements, but allows for easy explicit reuse of already-defined methods. That would be VERY nice to have. More than once I ended up writing a private function that I then called from several methods in the same multimethod, to avoid code duplication. - Currently, a preference doesn't encompass the path through the preferred value to its ancestors, but could. - If you have a set of common preferences, there's no easy way to create them in advance and share them among methods. There are issues here related to ensuring preference consistency and caching. At the moment, a multimethod takes two dispatch-oriented parameters: a hierarchy and a dispatch function that returns a single item from the hierarchy. How about generalizing the dispatch function in two ways: - it can return a sequence of items that will be tried in order - it can access the hierarchy Accessing the hierarchy is a minor point since this is already possible (write a dispatch function that uses parents, ancestors, etc.; for a hierarchy other than the global one, make the dispatch function a closure that refers to the hierarchy). Maybe it could be made more convenient. Returning a sequence should be sufficient to let the dispatch function handle any kind of preference. prefer-method could thus go away. Instead, there would be a set of utility functions to facilitate writing dispatch functions for common cases. A single dispatch function could be used for any number of multimethods. I think this should be sufficient to cover all cases you mentioned, but of course it needs to be tried in practice. I think the orthogonal elements of multifunction dispatch are type computations, traversals, and matchers (and the functions being dispatched to, of course). Dispatch function is maybe an unfortunate name; those functions aren't dispatchers, they're type-returning functions--functions that compute selector values. If you have a way to compute selector values from inputs and a way to specify the order in which matches against them will be tried, and a way to specify how matching is to be performed, then you have the tools to specify any dispatching algorithm you like. Clojure presently provides some tools for this: dispatch functions are type-returning functions; hierarchies are graphs of selector values; isa? and prefer- method are a control language for describing traversal, and isa? is also a matching function. But these are restricted versions: dispatch functions are meant to return a restricted range of values--symbols, keywords, classes, and certain collections of those values; multifunction dispatch supports hierarchies, but not other kinds of graphs; isa? and prefer-method are the only vocabulary we have for describing traversal, and isa? is the only matcher (almost the first thing I wanted to do when using MultiFns was replace isa? with my own matching function). The tools can be more expressive. Multifunction dispatch can be built on user-specified traversals of user-designed graphs of selector values, computed by user-supplied type-returning functions, and using user-specified matchers. The traversal order, the range of selector values, the language for describing traversal, and the matching procedure can all be more first-class and more orthogonal. Special cases can be provided for specific combinations known to be especially useful or efficient. With a full set of tools for describing dispatch, any differences of individual taste in function dispatching and type relationships becomes moot, because the tools are there to implement whatever type relationships and dispatching algorithm you want. Rich doesn't want to enshrine a particular traversal order in Clojure; I want the power to comprehensively specify traversal order in advance for certain uses; very well, any traversal order (or no traversal order) may be defined, as you like. He wants function dispatching and data definitions to be separated and so do I; very well, we have the freedom to compute whatever values we wish for use as types, and to arrange them in whatever sorts of graphs we like. Everyone wants things to be efficient, and likely people also want common use cases to be provided ready-to-wear; very well, those cases can be provided as built-ins or elements of libraries, with special treatment in
Re: Parameter ordering on map/reduce
I think clojure is a little torn between functional thinking and oo thinking - java vs haskell (i must admit that I am not originally a lisper, more of a java and functional guy) Functional / haskell style is what you see in map. that collection is at the end. The preceding arguments are like parameters for the function, suited for partial invocations map f coll take 10 coll java (or maybe oo) style is to think abvout the object as the first parameter conj coll e nth coll 10 I think it is not so intuitive If the function exist in the functional world (reduce filter map cons..) then the collection is at the end, otherwise it tends to be the first parameter. But, of course, if the function has a variable length argument list, that must be at the end --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: Possible Solution for Left-Right Precedence and More when using Multimethods? (was re: oo)
On Mar 31, 2:18 pm, mikel mev...@mac.com wrote: On Mar 31, 11:45 am, Konrad Hinsen konrad.hin...@laposte.net wrote: On Mar 31, 2009, at 16:32, Rich Hickey wrote: Here are some problems/limitations of existing OO/GF systems that I don't intend to repeat: ... I agree that these are not desirable features. I have had to work around some of them many times in the past. Traditional OO combines aspects that should better be handled separately. Here are the areas I'm looking to improve: - There's no easy way to talk about the method you would get if you were dispatch value X. Note that this is not the same as call-next- method, which reintroduces global ordering requirements, but allows for easy explicit reuse of already-defined methods. That would be VERY nice to have. More than once I ended up writing a private function that I then called from several methods in the same multimethod, to avoid code duplication. - Currently, a preference doesn't encompass the path through the preferred value to its ancestors, but could. - If you have a set of common preferences, there's no easy way to create them in advance and share them among methods. There are issues here related to ensuring preference consistency and caching. At the moment, a multimethod takes two dispatch-oriented parameters: a hierarchy and a dispatch function that returns a single item from the hierarchy. How about generalizing the dispatch function in two ways: - it can return a sequence of items that will be tried in order - it can access the hierarchy Accessing the hierarchy is a minor point since this is already possible (write a dispatch function that uses parents, ancestors, etc.; for a hierarchy other than the global one, make the dispatch function a closure that refers to the hierarchy). Maybe it could be made more convenient. Returning a sequence should be sufficient to let the dispatch function handle any kind of preference. prefer-method could thus go away. Instead, there would be a set of utility functions to facilitate writing dispatch functions for common cases. A single dispatch function could be used for any number of multimethods. I think this should be sufficient to cover all cases you mentioned, but of course it needs to be tried in practice. I think the orthogonal elements of multifunction dispatch are type computations, traversals, and matchers (and the functions being dispatched to, of course). What about predicate, or rule based dispatch - why hardwire the notion of types, traversal or matching? Dispatch function is maybe an unfortunate name; those functions aren't dispatchers, they're type-returning functions--functions that compute selector values. If you have a way to compute selector values from inputs and a way to specify the order in which matches against them will be tried, and a way to specify how matching is to be performed, then you have the tools to specify any dispatching algorithm you like. Clojure presently provides some tools for this: dispatch functions are type-returning functions; hierarchies are graphs of selector values; isa? and prefer- method are a control language for describing traversal, and isa? is also a matching function. But these are restricted versions: dispatch functions are meant to return a restricted range of values--symbols, keywords, classes, and certain collections of those values; multifunction dispatch supports hierarchies, but not other kinds of graphs; isa? and prefer-method are the only vocabulary we have for describing traversal, and isa? is the only matcher (almost the first thing I wanted to do when using MultiFns was replace isa? with my own matching function). The tools can be more expressive. Multifunction dispatch can be built on user-specified traversals of user-designed graphs of selector values, computed by user-supplied type-returning functions, and using user-specified matchers. The traversal order, the range of selector values, the language for describing traversal, and the matching procedure can all be more first-class and more orthogonal. Special cases can be provided for specific combinations known to be especially useful or efficient. With a full set of tools for describing dispatch, any differences of individual taste in function dispatching and type relationships becomes moot, because the tools are there to implement whatever type relationships and dispatching algorithm you want. Rich doesn't want to enshrine a particular traversal order in Clojure; I want the power to comprehensively specify traversal order in advance for certain uses; very well, any traversal order (or no traversal order) may be defined, as you like. He wants function dispatching and data definitions to be separated and so do I; very well, we have the freedom to compute whatever values we wish for use as types, and to arrange them in whatever sorts
Re: Possible Solution for Left-Right Precedence and More when using Multimethods? (was re: oo)
On 31.03.2009, at 18:50, Mark Engelberg wrote: On Tue, Mar 31, 2009 at 9:45 AM, Konrad Hinsen konrad.hin...@laposte.net wrote: I think this should be sufficient to cover all cases you mentioned, but of course it needs to be tried in practice. I think your idea of specifying a sequence of items to try in the dispatching function, at the point of definition for the multimethod, violates the principle of allowing library consumers to easily extend this on their own without having to contact the library designer. Maybe I wasn't clear about one point: the return sequence is not the sequence of concrete implementations to try (the dispatch function wouldn't even necessarily know them), but a sequence of starting points in the hierarchy from which the standard lookup would start. Konrad. --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: Parameter ordering on map/reduce
The let- macro looks very useful. Thank-you! --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: Scala vs Clojure
I was searching for a Java alternative for our medical bus product and looked at Scala during summer 2008. I found it was too tied to an object model. The lack of a complete macro system was in my view also a short coming. I concluded that it was not a significant departure from Java. I really wanted an alternative that shortened the project time line while providing future growth and a better concurrency model. Looked also at Erlang for better concurrency but found it was too foreign to the Java world and that we would end up coding a lot more. I then looked at Lisp alternatives running on the JVM and I stepped on Clojure while searching. We now start all our projects using Clojure and thunk down to Spring/Java when needed. It's a hell of a combination up to now :))) In terms of maturity age is not the significant factor. The more complex is the core of your new language, the bigger it is, the harder it it to get it out and stabilize it. Clojure has a small footprint/syntax, is extensible easily and can use the existing Java library base transparently. Stability wise, Clojure has been conceived by one guy, Rich. There is nothing more painful than developing by consensus. Endless discussions, addition bits by bits of new concepts, twisted solutions, I believe that a single person should lead the way. Listening to other ideas is fine and integrating the best of them is the way to go but the final decisions have to rest in a single pair of hands otherwise the product becomes chaotic and points in every directions. Luc On Tue, 2009-03-31 at 17:44 +0200, Christian Vest Hansen wrote: On Tue, Mar 31, 2009 at 5:20 PM, Chas Emerick cemer...@snowtide.com wrote: We shipped production software built in Scala last year, but likely will never do so again given clojure. Our primary motivating factor is the degree of complexity in the Scala, but since you're looking for auxiliary factors: - clojure has a far richer ecosystem -- there's a metric ton of community-contributed libraries and lots of people moving in very interesting directions. Maybe I missed them, or they've sprung up since I moved over to clojure last summer, but I've not seen a lot of scala libraries floating around. - clojure's community is, in general, more friendly, more helpful. There are certainly lots of pleasant people in the scala world, too, but I've yet to see a pissing match in #clojure, whereas #scala has had a number of them (despite the former being more heavily populated). I attribute this to the attitudes, demeanor, and near- constant presence of Rich and other core contributors. I find myself caught by surprise by these observations, as Scala has been covered in the media for a longer period of time. I don't know about the availability of 3'rd party libraries, but the IRC numbers, as of right now, is certainly correct. It could be taken to indicate that Clojure has a greater momentum than Scala. - The tooling story is roughly equivalent, I think. Neither community has a home-run effort, but both have lots of promising contenders for various IDEs. All of the above is obviously, gratuitously IMHO. - Chas On Mar 27, 2009, at 4:20 PM, Jon Harrop wrote: Can anyone who has tried both of these languages to a decent degree compare them in practical terms? In other words, I am not interested in the technical aspects of the languages themselves (e.g. dynamic vs static typing) but things like IDE support, tools (lexers and parsers), standard libraries, books and their quality, existing commercial applications and the commercial viability of shipping products targeted at their programmers (e.g. libraries)? I've never done anything significant on the JVM so I'm interested in picking one of these two languages and shipping a product for it. I've done a lot of commercial work with F# over the past 2 years but all Microsoft- related sales have died this year so I'm looking to diversify... Many thanks, -- Dr Jon Harrop, Flying Frog Consultancy Ltd. http://www.ffconsultancy.com/?e Luc Préfontaine Armageddon was yesterday, today we have a real problem... --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: Fresh Clojure Tutorial
(i know this note of mine probably really doesn't help, but) But maybe such thing already exist in the Scheme/CommonLisp world, and could be used or be a source of inspiration ? i'm not totally sure what you have in mind, but the subject of new researchy approach to doing GUIs that is supposed to be better than everything else before is a depressingly common subject matter, i think, given the actual approaches that ends up really being used most often. there's stuff like Adobe's http://lambda-the-ultimate.org/node/563. there's stuff like FRP in Haskell or PLT-Scheme. there's stuff like JavaFX (or whatever it is called this week). there's stuff like X-Windows but driven sanely by Erlang rather than C. then there's all the stuff that never got used anywhere outside of academia. etc. sincerely. --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: Fresh Clojure Tutorial
Yes, you're certainly right, but I'm only 35 old, and I don't want to yet let my dreams behind me, given that I will certainly (I hope so!) play at least 35 more years in this industry :-) I was thinking about an approach that would leverage the kind of separation one can find in the industry such as GUI stuff in one file, backend stuff in another, but maybe reconciled thanks to judicious use of higher order functions and conscienscious application of macros. Something that can be thought of as workable specs for the GUI, where one does not have to switch language from one abstraction level to the other. -- Laurent 2009/4/1 Raoul Duke rao...@gmail.com (i know this note of mine probably really doesn't help, but) But maybe such thing already exist in the Scheme/CommonLisp world, and could be used or be a source of inspiration ? i'm not totally sure what you have in mind, but the subject of new researchy approach to doing GUIs that is supposed to be better than everything else before is a depressingly common subject matter, i think, given the actual approaches that ends up really being used most often. there's stuff like Adobe's http://lambda-the-ultimate.org/node/563. there's stuff like FRP in Haskell or PLT-Scheme. there's stuff like JavaFX (or whatever it is called this week). there's stuff like X-Windows but driven sanely by Erlang rather than C. then there's all the stuff that never got used anywhere outside of academia. etc. sincerely. --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: Fresh Clojure Tutorial
Yes, you're certainly right, but I'm only 35 old, and I don't want to yet let my dreams behind me, given that I will certainly (I hope so!) play at least 35 more years in this industry :-) i'd say both: a) that is good to hear, and i support such attitude! please go forth and invent, because you might well do something insightful and helpful to all. (let alone just have fun in the process.) b) but! please don't forget to try to learn from what other people have done, especially mistakes made, or long-term problems that arise. which probably means: find somebody who really knows the breadth of gui research. you'd hope there'd already be such a person on a list like this? :-) sincerely. --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: Fresh Clojure Tutorial
On 01/04/2009, at 10:47 AM, Laurent PETIT wrote: Something that can be thought of as workable specs for the GUI, where one does not have to switch language from one abstraction level to the other. You should have a look at the Scala wrapping of SWT. Antony Blakey - CTO, Linkuistics Pty Ltd Ph: 0438 840 787 A Buddhist walks up to a hot-dog stand and says, Make me one with everything. He then pays the vendor and asks for change. The vendor says, Change comes from within. --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: Scala vs Clojure
On 01/04/2009, at 10:01 AM, e wrote: but the InteliJ IDE isn't free, is it? So what? I'm a professional developer. I make money using these tools. The money people pay for IntelliJ is one reason that the Scala support in IntelliJ is more ambitious and why the IntelliJ Clojure plugin is more advanced. I'd happily pay for NetBeans or Eclipse, and/or support for Clojure and Scala. I buy a lot of software, and when I use good O/ S software, I donate $ to support it e.g. Firebug. IntelliJ is cheap for a personal license (USD$249). Even VisualWorks Smalltalk, for which I pay 5% of my gross billings, is good deal because the productivity benefits pay for themselves. Antony Blakey - CTO, Linkuistics Pty Ltd Ph: 0438 840 787 He who would make his own liberty secure, must guard even his enemy from repression. -- Thomas Paine --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: I need help tracking down a performance problem.
Thanks to cl-format: (fn [buf__2572__auto__ len__2573__auto__] (if (= len__2573__auto__ 1) (mask8 (. buf__2572__auto__ (get))) (let [arr__2574__auto__ (int-array len__2573__auto__)] (dotimes [i__2575__auto__ len__2573__auto__] (aset-int arr__2574__auto__ i__2575__auto__ (mask8 (. buf__2572__auto__ (get) arr__2574__auto__))) This is the expansion for (make-reader get mask8), where were you attempting putting the int coercion to to the mask-fn? David On Tue, Mar 31, 2009 at 11:38 AM, Vincent Foley vfo...@gmail.com wrote: I tried using aset-int and I tried using int to coerce the result of mask-fn, the input argument to mask-fn and few other things, but none of that seems to make a difference so far. Mind you, this is an aspect of Clojure that I find a little confusing, so I'm just putting int calls here and there and looking at what happens. On Mar 31, 10:46 am, Christophe Grand christo...@cgrand.net wrote: Did you try to coerce the result of (~mask-fn ...) with int? (or use aset-int as suggested by David) On Tue, Mar 31, 2009 at 4:17 PM, Vincent Foley vfo...@gmail.com wrote: No, but in my defense I did not know such a function existed :) I'll give it a whirl and report back! On Mar 31, 9:57 am, David Nolen dnolen.li...@gmail.com wrote: Did you try using aset-int instead of aset? On Tue, Mar 31, 2009 at 8:25 AM, Vincent Foley vfo...@gmail.com wrote: For those interested, I managed to improve the performance of my original program from 2 minutes 40 seconds to decode 1000+ files down to 2 minutes. I'm still far from my goal, but it's an improvement, especially since the code is shorter and (IMO) cleaner. You can see it here: http://bitbucket.org/gnuvince/clj-starcraft/src/tip/src/starcraft/rep. .. And here's another question, running the program with -Xprof shows that nearly 20% of my execution time is spent calling java.lang.reflect.Array.set. Is there something wrong with the way I type hint my array in make-reader? Thanks, Vincent. On Mar 19, 8:12 pm, Vincent Foley vfo...@gmail.com wrote: Hello, For the past few days, I've been trying, unsuccessfully, to make an application I wrote faster. A Java program that performs, more or less, the same task takes 12 seconds (on my machine) to parse 1000 files; my Clojure program takes nearly 3 minutes. This more than an order of magnitude slower! Using the profiling tools available with the JVM, I quickly determined which function was the costliest. I copied it into a simple script file to profile it in isolation. I have made the script and the profile results (long!) available at this URL:http://gist.github.com/82136 I'm finding the results puzzling: is dereferencing a var *that* expensive? Can anyone tell me if they see something fundamentally wrong with my approach that would explain this abysmal performance? Thank you, Vincent. P.S.: I am using Sun's JVM 1.6.0_10 as shipped in Ubuntu Ibex. My machine is an Athlon 64 X2 4200+ with 3 GB of RAM. --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: I need help tracking down a performance problem.
I tried surrounding the call to the (. buf# (get)) method and putting the coercion directly inside the mask8 and mask16 functions. Neither worked. I want to mention at this point that I have *warn-on- reflection* set to true for the little script that uses the library and it doesn't report any call to methods that it can't resolve. Here's the complete -Xprof output, if it helps. Flat profile of 176.10 secs (11351 total ticks): main Interpreted + native Method 4.5% 511 + 0java.lang.Integer.hashCode 1.4% 160 + 0java.lang.Integer.intValue 0.8%91 + 0starcraft.replay.unpack $decode_command_block__94.invoke 0.7%80 + 0clojure.lang.Numbers.int_array 0.2%25 + 0clojure.lang.PersistentVector.pushTail 0.1%15 + 2java.lang.ClassLoader.defineClass1 0.1%16 + 0 hu.belicza.andras.bwhf.control.BinReplayUnpacker.esi28 0.1% 4 +11clojure.core__init.load 0.1%10 + 0clojure.lang.PersistentVector.cons 0.1% 8 + 0starcraft.replay.actions$fn__71.invoke 0.1% 8 + 0 hu.belicza.andras.bwhf.control.BinReplayUnpacker.unpackSection 0.1% 0 + 7java.lang.reflect.Array.setInt 0.1% 7 + 0clojure.lang.PersistentHashMap $BitmapIndexedNode.create 0.1% 7 + 0clojure.lang.RestFn.invoke 0.1% 7 + 0clojure.lang.RestFn.invoke 0.1% 7 + 0starcraft.replay.unpack $decode_commands__99.invoke 0.1% 7 + 0starcraft.replay.parse $parse_buffer__53$fn__56.invoke 0.1% 6 + 0clojure.lang.AFn.applyToHelper 0.1% 6 + 0clojure.lang.PersistentArrayMap.assoc 0.1% 6 + 0clojure.lang.PersistentHashMap $BitmapIndexedNode.assoc 0.0% 0 + 5java.lang.reflect.Array.newArray 0.0% 0 + 5java.lang.Class.forName0 0.0% 0 + 5java.util.zip.Inflater.inflateBytes 0.0% 5 + 0java.lang.AbstractStringBuilder.init 0.0% 5 + 0java.util.Arrays.copyOfRange 10.9% 1157 +76Total interpreted (including elided) Compiled + native Method 10.4% 1183 + 1starcraft.replay.parse$fn__23$fn__49.invoke 10.0% 1123 +17starcraft.replay.unpack $decode_command_block__94.invoke 9.2% 1043 + 0clojure.core$next__3096.invoke 8.9% 1014 + 0starcraft.replay.parse $parse_buffer__53$fn__56.invoke 5.5% 626 + 0clojure.lang.PersistentArrayMap.assoc 4.3% 474 +17clojure.lang.PersistentArrayMap.assoc 4.1% 464 + 7clojure.lang.RestFn.invoke 2.9% 333 + 0clojure.lang.Cons.next 2.5% 288 + 0clojure.lang.RT.seq 2.4% 269 + 0clojure.lang.AFn.applyToHelper 2.2% 249 + 0 hu.belicza.andras.bwhf.control.BinReplayUnpacker.unpackRepChunk 1.8% 202 + 0clojure.core$seq__3112.invoke 1.6% 174 + 3clojure.lang.RestFn.applyTo 1.3% 140 + 2clojure.lang.APersistentMap.cons 1.2% 130 + 1clojure.core$spread__3225.invoke 1.1% 127 + 0clojure.lang.PersistentStructMap.valAt 0.8%93 + 0clojure.core$reduce__3304.invoke 0.6%66 + 2starcraft.replay.unpack $decode_commands__99.invoke 0.6%63 + 0clojure.lang.PersistentArrayMap.valAt 0.1%13 + 1clojure.core$conj__3100.invoke 0.1% 9 + 0clojure.lang.APersistentMap.invoke 0.1% 3 + 6starcraft.replay.parse $fn__23$read_shorts__37.invoke 0.1% 8 + 0clojure.core$nthnext__4405.invoke 0.1% 0 + 7clojure.lang.ArraySeq.next 0.0% 0 + 5clojure.lang.APersistentVector.assoc 72.3% 8126 +76Total compiled (including elided) Stub + native Method 15.1% 0 + 1711java.lang.reflect.Array.setInt 1.2% 0 + 135java.lang.System.arraycopy 0.3% 0 +31java.lang.reflect.Array.set 0.1% 0 +15java.io.FileInputStream.readBytes 0.1% 0 +13java.lang.reflect.Array.get 0.1% 0 + 7java.lang.Object.getClass 0.0% 0 + 1java.lang.Thread.currentThread 16.9% 0 + 1913Total stub Thread-local ticks: 0.0% 1 Class loader 0.0% 2 Unknown: no last frame Flat profile of 0.01 secs (1 total ticks): DestroyJavaVM Thread-local ticks: 100.0% 1 Blocked (of total) Global summary of 176.12 seconds: 100.0% 11603 Received ticks 2.1% 246 Received GC ticks 4.3% 495 Compilation 0.0% 2 Other VM operations 0.0% 1 Class loader 0.0% 2 Unknown code 176.257 secs On Mar 31, 8:57 pm, David Nolen dnolen.li...@gmail.com wrote: Thanks to cl-format: (fn [buf__2572__auto__ len__2573__auto__] (if (= len__2573__auto__ 1) (mask8 (. buf__2572__auto__ (get))) (let [arr__2574__auto__ (int-array
Re: I need help tracking down a performance problem.
Did you try (int (mask8 (. buf__2572__auto__ (get ? Your macro should like this: (defmacro make-reader [get-fn mask-fn] `(fn [#^ByteBuffer buf# len#] (if (= len# 1) (~mask-fn (. buf# (~get-fn))) (let [#^[I arr# (int-array len#)] (dotimes [i# len#] (aset-int arr# i# (int (~mask-fn (. buf# (~get-fn)) arr# On Tue, Mar 31, 2009 at 9:09 PM, Vincent Foley vfo...@gmail.com wrote: I tried surrounding the call to the (. buf# (get)) method and putting the coercion directly inside the mask8 and mask16 functions. Neither worked. I want to mention at this point that I have *warn-on- reflection* set to true for the little script that uses the library and it doesn't report any call to methods that it can't resolve. Here's the complete -Xprof output, if it helps. Flat profile of 176.10 secs (11351 total ticks): main Interpreted + native Method 4.5% 511 + 0java.lang.Integer.hashCode 1.4% 160 + 0java.lang.Integer.intValue 0.8%91 + 0starcraft.replay.unpack $decode_command_block__94.invoke 0.7%80 + 0clojure.lang.Numbers.int_array 0.2%25 + 0clojure.lang.PersistentVector.pushTail 0.1%15 + 2java.lang.ClassLoader.defineClass1 0.1%16 + 0 hu.belicza.andras.bwhf.control.BinReplayUnpacker.esi28 0.1% 4 +11clojure.core__init.load 0.1%10 + 0clojure.lang.PersistentVector.cons 0.1% 8 + 0starcraft.replay.actions$fn__71.invoke 0.1% 8 + 0 hu.belicza.andras.bwhf.control.BinReplayUnpacker.unpackSection 0.1% 0 + 7java.lang.reflect.Array.setInt 0.1% 7 + 0clojure.lang.PersistentHashMap $BitmapIndexedNode.create 0.1% 7 + 0clojure.lang.RestFn.invoke 0.1% 7 + 0clojure.lang.RestFn.invoke 0.1% 7 + 0starcraft.replay.unpack $decode_commands__99.invoke 0.1% 7 + 0starcraft.replay.parse $parse_buffer__53$fn__56.invoke 0.1% 6 + 0clojure.lang.AFn.applyToHelper 0.1% 6 + 0clojure.lang.PersistentArrayMap.assoc 0.1% 6 + 0clojure.lang.PersistentHashMap $BitmapIndexedNode.assoc 0.0% 0 + 5java.lang.reflect.Array.newArray 0.0% 0 + 5java.lang.Class.forName0 0.0% 0 + 5java.util.zip.Inflater.inflateBytes 0.0% 5 + 0java.lang.AbstractStringBuilder.init 0.0% 5 + 0java.util.Arrays.copyOfRange 10.9% 1157 +76Total interpreted (including elided) Compiled + native Method 10.4% 1183 + 1starcraft.replay.parse$fn__23$fn__49.invoke 10.0% 1123 +17starcraft.replay.unpack $decode_command_block__94.invoke 9.2% 1043 + 0clojure.core$next__3096.invoke 8.9% 1014 + 0starcraft.replay.parse $parse_buffer__53$fn__56.invoke 5.5% 626 + 0clojure.lang.PersistentArrayMap.assoc 4.3% 474 +17clojure.lang.PersistentArrayMap.assoc 4.1% 464 + 7clojure.lang.RestFn.invoke 2.9% 333 + 0clojure.lang.Cons.next 2.5% 288 + 0clojure.lang.RT.seq 2.4% 269 + 0clojure.lang.AFn.applyToHelper 2.2% 249 + 0 hu.belicza.andras.bwhf.control.BinReplayUnpacker.unpackRepChunk 1.8% 202 + 0clojure.core$seq__3112.invoke 1.6% 174 + 3clojure.lang.RestFn.applyTo 1.3% 140 + 2clojure.lang.APersistentMap.cons 1.2% 130 + 1clojure.core$spread__3225.invoke 1.1% 127 + 0clojure.lang.PersistentStructMap.valAt 0.8%93 + 0clojure.core$reduce__3304.invoke 0.6%66 + 2starcraft.replay.unpack $decode_commands__99.invoke 0.6%63 + 0clojure.lang.PersistentArrayMap.valAt 0.1%13 + 1clojure.core$conj__3100.invoke 0.1% 9 + 0clojure.lang.APersistentMap.invoke 0.1% 3 + 6starcraft.replay.parse $fn__23$read_shorts__37.invoke 0.1% 8 + 0clojure.core$nthnext__4405.invoke 0.1% 0 + 7clojure.lang.ArraySeq.next 0.0% 0 + 5clojure.lang.APersistentVector.assoc 72.3% 8126 +76Total compiled (including elided) Stub + native Method 15.1% 0 + 1711java.lang.reflect.Array.setInt 1.2% 0 + 135java.lang.System.arraycopy 0.3% 0 +31java.lang.reflect.Array.set 0.1% 0 +15java.io.FileInputStream.readBytes 0.1% 0 +13java.lang.reflect.Array.get 0.1% 0 + 7java.lang.Object.getClass 0.0% 0 + 1java.lang.Thread.currentThread 16.9% 0 + 1913Total stub Thread-local ticks: 0.0% 1 Class loader 0.0% 2 Unknown: no last frame Flat profile of 0.01 secs (1 total ticks): DestroyJavaVM Thread-local ticks: 100.0% 1 Blocked (of total) Global summary of 176.12 seconds: 100.0% 11603 Received
Re: Scala vs Clojure
Unless they slowed down, the pace in which Enclojure was improving would put me dead on. I personally use IntelliJ IDEA. But who says I paid for it? On Mar 31, 5:45 pm, Antony Blakey antony.bla...@gmail.com wrote: On 28/03/2009, at 5:21 PM, Rayne wrote: I'd say Enclojure is close to production-ready. From my playing with it, plus the list of things not yet done, I don't think this is true. The IntelliJ clojure support seems more advanced right now, and I'm starting to use that in production. IMO the new NetBeans 6.7 LF on OSX now looks better than any other java IDE on OSX (but enclojure doesn't run on it). If enclojure did formatting and ran on 6.7 I'd probably choose that for Clojure development, although another consideration is that if you want to do mixed Scala/Clojure development, IntelliJ's Scala support has considerably loftier goals than Eclipse/NetBeans e.g. first-class support for the language model wrt refactoring etc. Antony Blakey -- CTO, Linkuistics Pty Ltd Ph: 0438 840 787 Lack of will power has caused more failure than lack of intelligence or ability. -- Flower A. Newhouse --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: I need help tracking down a performance problem.
15.1% 0 + 1711java.lang.reflect.Array.setInt Is definitely pointing at the aset-int as being the time gobbler, I think the expression in the macro should be this (aset-int (ints arr#) i# (int (~mask-fn (. buf# (~get-fn) to be extra safe. On Tue, Mar 31, 2009 at 10:00 PM, Vincent Foley vfo...@gmail.com wrote: I tried it just now; it made no difference. Nevertheless, thank you for you help and time! On Mar 31, 9:38 pm, David Nolen dnolen.li...@gmail.com wrote: Did you try (int (mask8 (. buf__2572__auto__ (get ? Your macro should like this: (defmacro make-reader [get-fn mask-fn] `(fn [#^ByteBuffer buf# len#] (if (= len# 1) (~mask-fn (. buf# (~get-fn))) (let [#^[I arr# (int-array len#)] (dotimes [i# len#] (aset-int arr# i# (int (~mask-fn (. buf# (~get-fn)) arr# On Tue, Mar 31, 2009 at 9:09 PM, Vincent Foley vfo...@gmail.com wrote: I tried surrounding the call to the (. buf# (get)) method and putting the coercion directly inside the mask8 and mask16 functions. Neither worked. I want to mention at this point that I have *warn-on- reflection* set to true for the little script that uses the library and it doesn't report any call to methods that it can't resolve. Here's the complete -Xprof output, if it helps. Flat profile of 176.10 secs (11351 total ticks): main Interpreted + native Method 4.5% 511 + 0java.lang.Integer.hashCode 1.4% 160 + 0java.lang.Integer.intValue 0.8%91 + 0starcraft.replay.unpack $decode_command_block__94.invoke 0.7%80 + 0clojure.lang.Numbers.int_array 0.2%25 + 0clojure.lang.PersistentVector.pushTail 0.1%15 + 2java.lang.ClassLoader.defineClass1 0.1%16 + 0 hu.belicza.andras.bwhf.control.BinReplayUnpacker.esi28 0.1% 4 +11clojure.core__init.load 0.1%10 + 0clojure.lang.PersistentVector.cons 0.1% 8 + 0starcraft.replay.actions$fn__71.invoke 0.1% 8 + 0 hu.belicza.andras.bwhf.control.BinReplayUnpacker.unpackSection 0.1% 0 + 7java.lang.reflect.Array.setInt 0.1% 7 + 0clojure.lang.PersistentHashMap $BitmapIndexedNode.create 0.1% 7 + 0clojure.lang.RestFn.invoke 0.1% 7 + 0clojure.lang.RestFn.invoke 0.1% 7 + 0starcraft.replay.unpack $decode_commands__99.invoke 0.1% 7 + 0starcraft.replay.parse $parse_buffer__53$fn__56.invoke 0.1% 6 + 0clojure.lang.AFn.applyToHelper 0.1% 6 + 0clojure.lang.PersistentArrayMap.assoc 0.1% 6 + 0clojure.lang.PersistentHashMap $BitmapIndexedNode.assoc 0.0% 0 + 5java.lang.reflect.Array.newArray 0.0% 0 + 5java.lang.Class.forName0 0.0% 0 + 5java.util.zip.Inflater.inflateBytes 0.0% 5 + 0java.lang.AbstractStringBuilder.init 0.0% 5 + 0java.util.Arrays.copyOfRange 10.9% 1157 +76Total interpreted (including elided) Compiled + native Method 10.4% 1183 + 1starcraft.replay.parse$fn__23$fn__49.invoke 10.0% 1123 +17starcraft.replay.unpack $decode_command_block__94.invoke 9.2% 1043 + 0clojure.core$next__3096.invoke 8.9% 1014 + 0starcraft.replay.parse $parse_buffer__53$fn__56.invoke 5.5% 626 + 0clojure.lang.PersistentArrayMap.assoc 4.3% 474 +17clojure.lang.PersistentArrayMap.assoc 4.1% 464 + 7clojure.lang.RestFn.invoke 2.9% 333 + 0clojure.lang.Cons.next 2.5% 288 + 0clojure.lang.RT.seq 2.4% 269 + 0clojure.lang.AFn.applyToHelper 2.2% 249 + 0 hu.belicza.andras.bwhf.control.BinReplayUnpacker.unpackRepChunk 1.8% 202 + 0clojure.core$seq__3112.invoke 1.6% 174 + 3clojure.lang.RestFn.applyTo 1.3% 140 + 2clojure.lang.APersistentMap.cons 1.2% 130 + 1clojure.core$spread__3225.invoke 1.1% 127 + 0clojure.lang.PersistentStructMap.valAt 0.8%93 + 0clojure.core$reduce__3304.invoke 0.6%66 + 2starcraft.replay.unpack $decode_commands__99.invoke 0.6%63 + 0clojure.lang.PersistentArrayMap.valAt 0.1%13 + 1clojure.core$conj__3100.invoke 0.1% 9 + 0clojure.lang.APersistentMap.invoke 0.1% 3 + 6starcraft.replay.parse $fn__23$read_shorts__37.invoke 0.1% 8 + 0clojure.core$nthnext__4405.invoke 0.1% 0 + 7clojure.lang.ArraySeq.next 0.0% 0 + 5clojure.lang.APersistentVector.assoc 72.3% 8126 +76Total compiled (including elided) Stub + native Method 15.1% 0 + 1711
Re: Scala vs Clojure
On 01/04/2009, at 1:26 PM, Rayne wrote: Unless they slowed down, the pace in which Enclojure was improving would put me dead on. Neither the site nor the mailing list shows a lot of activity - it's not dead, but it is taking a long time compared to the IntelliJ support, which was my point. I personally use IntelliJ IDEA. But who says I paid for it? I'm not sure what point you are making. Antony Blakey -- CTO, Linkuistics Pty Ltd Ph: 0438 840 787 Don't anthropomorphize computers. They hate that. --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: Gen-class, extending a parameterized type
That's exactly what I did; no issues. Thanks! On Mar 31, 1:47 pm, Stuart Sierra the.stuart.sie...@gmail.com wrote: As an interim solution, you could write a wrapper class in Java that extends the parameterized class, then extend that class in Clojure. -Stuart --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
- vs. comp
Hi folks, I have some code where I wanted to: - take a list of stuff (which includes another list inside) - use 'seq-utils/flatten' to flatten the list - use 'interpose' to add comma-delimiting strings between the elements - print out the results, thereby creating comma-delimited output I may choose between: ((comp (fn [x] (apply println x)) (fn [x] (interpose , x)) seq-utils/flatten) mr) OR (- mr seq-utils/flatten ((fn [x] (interpose , x))) ((fn [x] (apply println x And I found the - notation marginally easier to interpret and understand. Apart from appearance, are there any benefits to using - instead of the comp function? I happily concede that there exist nicer ways to achieve this goal, but the question I wanted to raise concerned the benefits of using - vs comp or vice-versa. Kev Kev --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
basic question on structuring refs
Hi - I'm struggling with what is probably a very basic STM problem... so forgive me if I've missed something obvious. I have a world that is a list of structures The world itself will change occasionally - i.e. I'll add or remove structures from the overall list, and I'll regularly be reading the whole list. However quite often I'll just want to change individual structures without affecting the rest of the world. So, putting this in terms of refs - do I use: (A) one ref for the whole world - in which case how do I stop parallel changes to two unrelated structures in the world from causing transaction retries? (B) one ref for each structure in the world - so the world list is a list of refs - but then how do I change the world itself? (C) both of the above - a ref for the world list which itself contains a list of refs to each structure I suspect the answer is 'c' - will this work? Or have I over complicated something somewhere? - Korny -- Kornelis Sietsma korny at my surname dot com Every jumbled pile of person has a thinking part that wonders what the part that isn't thinking isn't thinking of --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: - vs. comp
comp creates a new function that you can store. - threads a value through a series of expressions. On Wed, Apr 1, 2009 at 12:52 AM, kkw kevin.k@gmail.com wrote: Hi folks, I have some code where I wanted to: - take a list of stuff (which includes another list inside) - use 'seq-utils/flatten' to flatten the list - use 'interpose' to add comma-delimiting strings between the elements - print out the results, thereby creating comma-delimited output I may choose between: ((comp (fn [x] (apply println x)) (fn [x] (interpose , x)) seq-utils/flatten) mr) OR (- mr seq-utils/flatten ((fn [x] (interpose , x))) ((fn [x] (apply println x And I found the - notation marginally easier to interpret and understand. Apart from appearance, are there any benefits to using - instead of the comp function? I happily concede that there exist nicer ways to achieve this goal, but the question I wanted to raise concerned the benefits of using - vs comp or vice-versa. Kev Kev --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---
Re: Please suggest a way to learn just enough Java for Clojure
Thanks for all your replies. Using google for a solution on an as-when-needed basis does not really work well for me unless I have some conceptual understanding of the subject. Hence, for the time being, I have decided to settle for Core Java Vol. 1. From your replies, I think this should be a comprehensive intro. Once I go through this once, I hope I will be able to read _and_ understand the Java API. Regards, Santanu Chatterjee --~--~-~--~~~---~--~~ 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 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 -~--~~~~--~~--~--~---