Re: positions
My 'requirements' were not so much for any particular need, but to try to think up a logical and complete API for dealing with multisets. I agree that there should be an actual collection type for multisets (implemented as an underlying map of values to frequencies I presume); but you might as well also be allowed to pass any kind of collections and have it do something order-preserving with them. It makes a good gathering point for sequence functionalities as \well as handling multisets. Alex is right that the keep-likes-with-likes option is a little weird. I'm not sure whether to just conj them next to the first instance, or try to equally distribute them as much as possible throughout the instances, leaving any remainders on the initial ones. Probably the latter. Of course when you have this kind of questioning, maybe it is not a good fundamental functionality to add. (My original spur for this was in merging argument lists in a permissive argument list macro I'm working on; the idea was you would get 'rest' type parameters anywhere in the list there is a repetition of variables under a keyword. Obviously you wouldn't want to have disparate instances of the same thing here. (My initial thoughts on this macro are at the bottom of the most recent discussion of keyword arguments. (How, by the way, do you do "show quoted text"?)) There is a sort of hierarchy of sequences for being sensible for multiset operations. First we have multisets themselves. Then we have sequences that are ordered but have no dislocated repetition of elements. Then we have arbitrary sequences. I'm inclined to want an API that handles all three. Maybe someone who does a lot of statistical work would have a better idea of how this API should work. Sean, regarding doall, the reason I wanted to have an internal override is to be able to preserve the collection type of the arguments. Sometimes it gets a little annoying to cast these back every time; and when you're dealing with small sequences, laziness is not really necessary. If you wanted to be \really evil about it, you could have a bind-able variable *lazy* that sets it one way or the other. -- 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
Re: A macro for flexible keyword argument handling
I don't see why you couldn't simply check to make sure that there are no arguments without either default or supplied values. As I wrote above, "If you left the arguments incomplete and unkeyworded it would apply what you put preferentially to the first arguments in the list without a default value." If there are any null arguments left over, the macro could throw an exception. The basic rule is, "accept what you can, and only error our if you absolutely must." (Of course this variable application rule might get confusing in practice, at least without help from the IDE.) I think it's better than just a flat arguments list, because 1) it allows you to specify defaults and 2) it gives you the option of naming arguments by keyword. How can you do that with flat argument lists? My point is that the option of naming arguments is implicitly there any time you write a function, because variables have names; and there is no way to mistake a default value for a variable. So you might as well use these built-in distinctors. You could even do a little branching from within argument lists. Suppose for instance you had something like (dfnsk demo-branch [x 0 0 1 y 0 1 0] ) There can be only one default per variable, so what are the other values? These could only be possible passed-in values. x=0, y=1 is the first branch, x=1, y=0 is the second. Within the function body, you would have a predicate available that tells you what branch you are on, so for instance you could write something like (cond (branch? 1) ... (branch? 2) ...) or, if you passed in multiple function bodies after the argument list, (kind of like the variable arity thing), the first would be for the first branch, the second for the second, etc. Another 'generality' that could be added is to match arguments by type whenever there is a type annotation in the function definition and a discrepancy in the call; so for instance if you had a number of symbols that were supposed to be passed last, and you passed a symbol somewhere else, it would be applied to the first symbol-type argument in the function list without throwing an error. -- 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
repeatedly forcing the evaluation of a lazy seq
Hi all, Just ran into a small gotcha: I had an atom which contained a lazyseq (e.g. (filter males world)). Later on I would be repeatedly calling random elements from this atom, using clojure contrib rand-elt. That was surprisingly slow. I figured out that count was the culprit. Apparently, the lazyseq atom stayed a lazyseq atom (immutability), and each time I called for a random element, count had to do the whole filtering to figure out 'count'. Is there any way that I can get a warning printed out that would let me know when I am doing something stupid like this? for example: (repeatedly evaluating identical full lazy sequence @world)? -- 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
Re: A macro for flexible keyword argument handling
I should also add something I alluded to in another discussion (under 'positions'); this is the idea of making \any parameter into a rest parameter. For instance, if you had (defnsk add [addend augend] ...) you could call it like (add :addend 1 2 3 :augend 1 2) or (add [1 2 3] [1 2 3 4]). Must the poor programmer now check \all of his parameters to see if they have been magically turned into rest parameters without his knowing? Of course not! The function body is simply executed repeatedly, and the results put in a list: (add [1 2 3] [1 2 3 4]) -> [2 4 6] If we were being \really permissive, we might want to return \two results, one the straightforward element-by-element adding, the other the 'cartesian' adding: [[2 4 6],[[2 3 4 5][3 4 5 6][4 5 6 7]]]. Or we might allow a flag passed to all functions :cartesian :sequential to turn this behavior on or off. If function writers want to explicitly manipulate these sequences, of course, that is fine; all I am saying is that if they do nothing, the function \caller gets his sequence code for free. To assist this way of programming, it might be a good idea to have another type of 'permissive' sequence abstraction, which you might call for old time's sake car and cdr: (car [1 2 3]) -> 1 (cdr [1 2 3]) -> [2 3] (car 1) -> 1 (cdr 1) -> nil A direct reference to a sequence as if it were a singular element, meanwhile, is an invitation to deal with the sequence at the level of the function caller as we do above (who if he passes elements as a sequence, presumably knows what he is doing). I guess this is getting to be a pretty epic macro! I figured it was worth inviting boos and/or cheers and suggestions before setting out... -- 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
Suggestion: Add should_cache? flag to lazy-seq
This would solve the "holding to the head" problem. Many times, lazy-seq would be used without the need to get the same cell twice. In this case, avoiding cashing would both enhance performance and more importantly would avoid OutOfMemoryError Exceptions like in: (def r (repeatedly #(rand))) (last r) So, something like: (defn lazy-seq [should_cache? &body] .. would be beneficial (I think :) -- 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
Re: positions
If you think about it, the tower of sequence types is like this: seq | gathered seq /\ multiset permutation \ / set The way to do the various options I pointed out is to mix types: the keep-likes-with-likes would be (union ). take-away-all would be (difference ), while take- away-some would be (difference ). The problem is once you add seq on top, it gets a little defective, as Alex pointed out. (multiset ) is easy, as is (permutation ), but there's no unambiguous way of going from a seq to a permutation or to a gathered seq. The 'left' side of the tower is much happier than the right. It's also hard to sign an interpretation to all the combinations on the tower; for instance, what is the union of two permutations? This needs a little TLC from a category theorist... Nevertheless, this might be a good way of grouping functionalities into an API. The set API can be extended to all these types, and branch into additional combination operators as it moves up the tower (with really an infinite number for seqs). -- 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
Re: Suggestion: Add should_cache? flag to lazy-seq
On Nov 19, 11:52 am, Gabi wrote: > This would solve the "holding to the head" problem. > Many times, lazy-seq would be used without the need to get the same > cell twice. > In this case, avoiding cashing would both enhance performance and more > importantly would avoid OutOfMemoryError Exceptions like in: > > (def r (repeatedly #(rand))) > (last r) > > So, something like: > (defn lazy-seq [should_cache? &body] .. > would be beneficial (I think :) I can see how that would be useful in some cases, but I think it also would break the contract for seqs. They are supposed to be persistent. I think a stream abstraction was considered at one point, but scrapped in favour of chunked seqs. The solution is simply to avoid defining a global reference to a seq that might grow without bounds. Instead, define a function and just create a new seq every time you want fresh values. -- Jarkko -- 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
Re: A macro for flexible keyword argument handling
On Nov 20, 8:33 am, nchubrich wrote: > I guess this is getting to be a pretty epic macro! I figured it was > worth inviting boos and/or cheers and suggestions before setting out... Far be it from me to discourage making function invocation semantics more flexible! Just one thing: you've been calling your macro "defnsk", which makes it sound like a wrapper for the def form. Don't leave defmethod, fn, letfn, and every other way of making a function in the dust. :) -- 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
Re: [ANN] leiningen - a Clojure build tool
On Wed, Nov 18, 2009 at 2:29 AM, Phil Hagelberg wrote: > > With Leiningen, your build is described using Clojure. You can put any > code you like in your project.clj file; the only requirement is that > it includes a call to defproject. You can define your own tasks in > there if you need to, but the majority of projects should be able to > get by on the tasks that are provided with Leiningen. If you do find a > common task that you need to add, you can implement it as a plugin > rather than copying and pasting among each of your projects. This is outstanding; thank you! I'd love to see a short recipe on how to deploy a simple application (hello-world) into an executable jar using Leiningen. I've tried, but seem to be messing something up. Best, Graham -- 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
Re: leiningen - a Clojure build tool
The Incanter guys put something up: http://incanter-blog.org/2009/11/20/leiningen-clojars/ On Nov 20, 11:06 am, Graham Fawcett wrote: > On Wed, Nov 18, 2009 at 2:29 AM, Phil Hagelberg wrote: > > > With Leiningen, your build is described using Clojure. You can put any > > code you like in your project.clj file; the only requirement is that > > it includes a call to defproject. You can define your own tasks in > > there if you need to, but the majority of projects should be able to > > get by on the tasks that are provided with Leiningen. If you do find a > > common task that you need to add, you can implement it as a plugin > > rather than copying and pasting among each of your projects. > > This is outstanding; thank you! > > I'd love to see a short recipe on how to deploy a simple application > (hello-world) into an executable jar using Leiningen. I've tried, but > seem to be messing something up. > > Best, > Graham -- 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
Re: leiningen - a Clojure build tool
On Fri, Nov 20, 2009 at 11:11 AM, Sean Devlin wrote: > The Incanter guys put something up: > > http://incanter-blog.org/2009/11/20/leiningen-clojars/ Excellent, thanks! Leiningen + Clojars is a game-changer for Clojure. I'm very excited. Will-need-to-practice-spelling-leiningen'ly yours, Graham > > On Nov 20, 11:06 am, Graham Fawcett wrote: >> On Wed, Nov 18, 2009 at 2:29 AM, Phil Hagelberg wrote: >> >> > With Leiningen, your build is described using Clojure. You can put any >> > code you like in your project.clj file; the only requirement is that >> > it includes a call to defproject. You can define your own tasks in >> > there if you need to, but the majority of projects should be able to >> > get by on the tasks that are provided with Leiningen. If you do find a >> > common task that you need to add, you can implement it as a plugin >> > rather than copying and pasting among each of your projects. >> >> This is outstanding; thank you! >> >> I'd love to see a short recipe on how to deploy a simple application >> (hello-world) into an executable jar using Leiningen. I've tried, but >> seem to be messing something up. >> >> Best, >> Graham > > -- > 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 -- 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
Re: leiningen - a Clojure build tool
Something tells me we'll just be calling it 'lein'. Is that okay Phil? Sean On Nov 20, 11:21 am, Graham Fawcett wrote: > On Fri, Nov 20, 2009 at 11:11 AM, Sean Devlin > wrote: > > The Incanter guys put something up: > > >http://incanter-blog.org/2009/11/20/leiningen-clojars/ > > Excellent, thanks! > > Leiningen + Clojars is a game-changer for Clojure. I'm very excited. > > Will-need-to-practice-spelling-leiningen'ly yours, > Graham > > > > > On Nov 20, 11:06 am, Graham Fawcett wrote: > >> On Wed, Nov 18, 2009 at 2:29 AM, Phil Hagelberg wrote: > > >> > With Leiningen, your build is described using Clojure. You can put any > >> > code you like in your project.clj file; the only requirement is that > >> > it includes a call to defproject. You can define your own tasks in > >> > there if you need to, but the majority of projects should be able to > >> > get by on the tasks that are provided with Leiningen. If you do find a > >> > common task that you need to add, you can implement it as a plugin > >> > rather than copying and pasting among each of your projects. > > >> This is outstanding; thank you! > > >> I'd love to see a short recipe on how to deploy a simple application > >> (hello-world) into an executable jar using Leiningen. I've tried, but > >> seem to be messing something up. > > >> Best, > >> Graham > > > -- > > 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 -- 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
Re: leiningen - a Clojure build tool
FYI: http://www.infoq.com/news/2009/11/clojars-leiningen-clojure 2009/11/20 Sean Devlin : > Something tells me we'll just be calling it 'lein'. Is that okay > Phil? > > Sean > > On Nov 20, 11:21 am, Graham Fawcett wrote: >> On Fri, Nov 20, 2009 at 11:11 AM, Sean Devlin >> wrote: >> > The Incanter guys put something up: >> >> >http://incanter-blog.org/2009/11/20/leiningen-clojars/ >> >> Excellent, thanks! >> >> Leiningen + Clojars is a game-changer for Clojure. I'm very excited. >> >> Will-need-to-practice-spelling-leiningen'ly yours, >> Graham >> >> >> >> > On Nov 20, 11:06 am, Graham Fawcett wrote: >> >> On Wed, Nov 18, 2009 at 2:29 AM, Phil Hagelberg wrote: >> >> >> > With Leiningen, your build is described using Clojure. You can put any >> >> > code you like in your project.clj file; the only requirement is that >> >> > it includes a call to defproject. You can define your own tasks in >> >> > there if you need to, but the majority of projects should be able to >> >> > get by on the tasks that are provided with Leiningen. If you do find a >> >> > common task that you need to add, you can implement it as a plugin >> >> > rather than copying and pasting among each of your projects. >> >> >> This is outstanding; thank you! >> >> >> I'd love to see a short recipe on how to deploy a simple application >> >> (hello-world) into an executable jar using Leiningen. I've tried, but >> >> seem to be messing something up. >> >> >> Best, >> >> Graham >> >> > -- >> > 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 > > -- > 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 -- 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
Re: [ANN] Clojars - a Clojure community jar repository
FYI: http://www.infoq.com/news/2009/11/clojars-leiningen-clojure 2009/11/19 Alex Osborne : > Laurent PETIT wrote: >> Hello, >> >> Just an idea out of my head : could it be possible for the pom.xml to be >> included in the jar, in the META-INF/ directory ? >> >> This would even further simplify the process, wouldn't it ? :) > > That's a great idea! Can't believe it didn't occur to me. :-) > > I looks like Maven does this, it puts two files in the jar: > > META-INF/maven/$groupId/$artifactId/pom.xml > META-INF/maven/$groupId/$artifactId/pom.properties > > pom.properties contains: > > version=1.0.0 > groupId=mygroup > artifactId=myjar > > So it looks like you can use that to figure out what version a library > is just using the java properties system. We should make Leiningen do > the same. > > Alex > > -- > 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 -- 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
Re: A macro for flexible keyword argument handling
No, I'd rather not, but I have to take this in bite-size pieces. I'm still a bit of a noob at writing macros. I want to make it so that the user does not have to do anything aside from deal with the argument lists directly, so that means writing different macros for defn, letfn, defmethod, etc. Might as well try this on for size \one way first, and if nobody (including me) likes it, then there's no reason to continue the crusade -- 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
clojure-jsr223
Without knowing of Niels Mayer's work (until just now) I wrote an implementation of the Java Scripting API for Clojure --and even named it the same. Indeed great minds think alike. Though I didn't think of isolating the runtime in different instances of the engine. The distribution ZIP file has the clojure-jsr223.jar that goes alog with clojure.jar, the javadoc, sources and samples. You may get it here: http://code.google.com/p/clojure-jsr223/downloads/list You can run code, set bindings, call functions, get interface implementations, compile libs, and get some info from the factory. The engine will redirect in/out/err according to what's in the SimpleScriptContext argument, whose defaults have no effect on the RT. I hope this will be useful. I'll check-in the source in google code as soon as they resolve some issue with the repository. Will appreciate suggestions on how to better do the work of wrapping the RT. For example, to get an implementation of a Java interface, the library requires that something like this has bee previously evaluated: ... (def ActionListenerImpl (proxy [ActionListener] [] (actionPerformed [evt] (println \"button pushed\" and then you do: ... button.addActionListener(invoke.getInterface(ActionListener.class)); So with this convention, the library looks for a var named after the required interface plus the Impl suffix. (Or invoke.getInterface ("other.ns", ActionListener.class) if it's in a namespace other than user.) Why a var and not a function? I'm not so sure why now; it may was well be a function. I guess I thought it'd help to make it a bit different than your other functions. Here's some sample from the JDK but changed for Clojure: ScriptEngineManager factory = new ScriptEngineManager(); ScriptEngine engine = factory.getEngineByName("Clojure"); engine.eval("(println \"Hello, World\")"); engine.eval(new java.io.FileReader("code.clj"); String script = "(defn hello [name] (println \"Hello\" name))"; engine.eval(script); Invocable inv = (Invocable) engine; inv.invokeFunction("hello", "Scripting!!" ); File f = new File("samples/jsr223/ScriptVars.java"); engine.put("file", f); engine.eval("(println (.getAbsolutePath file))"); engine.eval( "(import java.awt.event.ActionListener)" + " (def ActionListenerImpl " + "(proxy [ActionListener] []" + " (actionPerformed [evt] " + "(println \"button pushed\""); Invocable invoke = (Invocable) engine; JFrame frame = new JFrame(); JButton button = new JButton("Push"); button.addActionListener(invoke.getInterface(ActionListener.class)); frame.getContentPane().add(button); frame.pack(); frame.setVisible(true); Compilable compile = (Compilable) engine; compile.compile("reader.snake"); -- 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
Re: take repeatedly alternative?
as an aside, sometimes you want the rng to be truly pure so you can easily recreate situations. take a look at randomness in haskell for fun. :-) -- 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
tree-shaking a jarred Clojure app?
Hi folks, This is somewhat a Java question, but it's in the context of Clojure, so here goes. Playing with Leiningen got me thinking about bundling a Clojure application as a JAR, which might include a host of classes that are loaded but never used. Is it possible to "tree-shake" such a jarfile, and eliminate any classes that are not required for the main-class' operation? (Assuming the program doesn't need 'eval' with access to all of those classes at runtime.) This might not save a lot of startup time, but where startup time matters, maybe it might shave off a meaningful fraction. I'm just curious whether there is enough dependency information in a set of class files to calculate a tree-shaking plan; and whether there are existing tools to do the job. Best, Graham -- 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
Re: tree-shaking a jarred Clojure app?
Hi Graham 2009/11/20 Graham Fawcett : > Hi folks, > > This is somewhat a Java question, but it's in the context of Clojure, > so here goes. Playing with Leiningen got me thinking about bundling a > Clojure application as a JAR, which might include a host of classes > that are loaded but never used. Is it possible to "tree-shake" such a > jarfile, and eliminate any classes that are not required for the > main-class' operation? (Assuming the program doesn't need 'eval' with > access to all of those classes at runtime.) > > This might not save a lot of startup time, but where startup time > matters, maybe it might shave off a meaningful fraction. I'm just > curious whether there is enough dependency information in a set of > class files to calculate a tree-shaking plan; and whether there are > existing tools to do the job. I might have misunderstood, but isn't the problem the same as in Java; you can't know from a static analysis which classes are going to be loaded? Best regards, jim -- 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
Re: leiningen - a Clojure build tool
Sean Devlin writes: > Something tells me we'll just be calling it 'lein'. Is that okay > Phil? Yeah, there's a reason the bin script is called "lein"... I was misspelling it myself for the first few days of working on it. =) -Phil -- 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
Re: [ANN] Clojars - a Clojure community jar repository
Alex Osborne writes: > I looks like Maven does this, it puts two files in the jar: > > META-INF/maven/$groupId/$artifactId/pom.xml > META-INF/maven/$groupId/$artifactId/pom.properties > > So it looks like you can use that to figure out what version a library > is just using the java properties system. We should make Leiningen do > the same. This is a solid idea; I will target it for leiningen 1.0. -Phil -- 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
Re: tree-shaking a jarred Clojure app?
On Fri, Nov 20, 2009 at 1:37 PM, Jim Downing wrote: > Hi Graham > > 2009/11/20 Graham Fawcett : >> Hi folks, >> >> This is somewhat a Java question, but it's in the context of Clojure, >> so here goes. Playing with Leiningen got me thinking about bundling a >> Clojure application as a JAR, which might include a host of classes >> that are loaded but never used. Is it possible to "tree-shake" such a >> jarfile, and eliminate any classes that are not required for the >> main-class' operation? (Assuming the program doesn't need 'eval' with >> access to all of those classes at runtime.) >> >> This might not save a lot of startup time, but where startup time >> matters, maybe it might shave off a meaningful fraction. I'm just >> curious whether there is enough dependency information in a set of >> class files to calculate a tree-shaking plan; and whether there are >> existing tools to do the job. > > I might have misunderstood, but isn't the problem the same as in Java; > you can't know from a static analysis which classes are going to be > loaded? If it's not possible in Java, then yes, it wouldn't be any different in Clojure. But after an admittedly casual search, I don't know what the specific blockers are to tree-shaking in Java. I know there are dynamic load-class-by-name facilities in the JVM, and of course that would be a barrier for static analysis. I've only ever seen these called with literal strings, though (e.g. in setting a JDBC driver), and that could be statically analyzed. But I should be able to know, through class inspection, whether my 'main' program depends on a class which uses, say, the clojure.zip namespace, and decide whether or not to include it. Or so I am wondering. I suppose a better question might be: would a tree-shaker have a reasonable chance of shaking a typical Clojure jar, or are there too many dynamic obstacles to a good analysis. Just curious, Graham > > Best regards, > > jim > > -- > 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 -- 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
Re: tree-shaking a jarred Clojure app?
> But I should be able to know, through class inspection, whether my > 'main' program depends on a class which uses, say, the clojure.zip > namespace, and decide whether or not to include it. Or so I am > wondering. There are impediments to that, too -- your namespace might require another, and so on, and your namespace can refer to symbols further down the chain without itself including the necessary `require` form. If you had the entire classpath available, and were willing to transitively examine the entire tree (probably including code-walking) then you might be able to solve this problem... but as soon as you hit a call to `read` where *read-eval* is not known to be false, or a call to `eval`, or maybe even some uses of reflection, you have to give up. Furthermore, some code adjusts itself at compile-time according to its environment (e.g., clojure.contrib.logging, which generates different functions depending on which logging libraries are available). That's not very amenable to static analysis. > I suppose a better question might be: would a tree-shaker have a > reasonable chance of shaking a typical Clojure jar, or are there too > many dynamic obstacles to a good analysis. I'm not sure it's worth solving this through low-level analysis. Far better, IMO, is to rely on correct descriptors and namespace definitions -- convention and configuration can save the day. If you can sweep the hard parts under the proverbial rug, the rest can be solved in a handful of lines of code! -- 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
Re: tree-shaking a jarred Clojure app?
On Fri, Nov 20, 2009 at 2:28 PM, Richard Newman wrote: >> I suppose a better question might be: would a tree-shaker have a >> reasonable chance of shaking a typical Clojure jar, or are there too >> many dynamic obstacles to a good analysis. > > I'm not sure it's worth solving this through low-level analysis. Far > better, IMO, is to rely on correct descriptors and namespace > definitions -- convention and configuration can save the day. If you > can sweep the hard parts under the proverbial rug, the rest can be > solved in a handful of lines of code! That's a great point. Thanks Richard and Jim for your thoughts! Best, Graham -- 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
Re: Datatypes and Protocols - early experience program
On Thu, Nov 19, 2009 at 12:39 PM, Krukow wrote: > On Nov 19, 12:01 am, samppi wrote: >> Question: are the general mechanisms for accessing and setting fields >> their keywords and assoc respectively: >> (deftype Bar [a b c d e]) >> (def b (Bar 1 2 3 4 5)) >> (:c b) >> (def c (assoc b :e 2)) >> Does (:c b) and (assoc b :e 2) take advantage of Bar's field >> information? Is it any faster than using an array map? Are there any >> equivalents to struct maps' accessor functions? My understanding is that if you have (:c b) somewhere in your code, and "b" is always an object of the same deftype with a field "c", you're getting Java field-speed access (once hotspot has done what it does). Yes, that's faster than array map lookup. It's even faster than struct map accessor function lookup. > You can use the ability to implement interfaces, specifically > automatic support for IPersistentMap: > > ser=> (deftype Bar [a b] [clojure.lang.IPersistentMap]) > #'user/Bar > user=> (assoc (Bar 1 2) :a 42) > #:Bar{:a 42, :b 2} > user=> > > I have a question here, though: what is this? > > ser=> (assoc (Bar 1 2) :c 42) > #:Bar{:a 1, :b 2, :c 42} > user=> #:Bar{:a 1, :b 2, :c 42} > > Is it a "Bar" with field-speed access to :a and :b and map-speed > access to :c? Yes, I think that's correct. > Also can I assume that > > (assoc (Bar 1 2) :a 42) > #:Bar{:a 42, :b 2} > > will share structure with the (Bar 1 2) and still has fast access > to :a? Is the assoc function using that :a is a field? There will be no shared structure between your two Bar object. That is, the reference to 2 (or the value 2 itself if it were a primitive) will be copied to the new object. > I guess I am just asking if the performance guarantees are those I > would expect of Clojure (i.e., "too fast" ;-)) This is definitely still too fast. In fact, it keeps getting worse. --Chouser -- 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
Re: Datatypes and Protocols - early experience program
On Nov 20, 8:51 pm, Chouser wrote: > On Thu, Nov 19, 2009 at 12:39 PM, Krukow wrote: [snip] > > I guess I am just asking if the performance guarantees are those I > > would expect of Clojure (i.e., "too fast" ;-)) > > This is definitely still too fast. In fact, it keeps getting worse. > > --Chouser We gotta stop him ;-) No, more seriously, I really like these new features. Not just for the speed, but for the modeling support. I'm wondering if I could get some feed-back on a defprotocol/deftype example. I am wondering if I am thinking "too object oriented" here and misusing the features, or if I am inline with the intended use of protocols and types. The example code is a "Circuit Breaker" (the stability pattern mentioned in Michael Nygaard's "Release It!"). Code: Circuit breaker states and transitions http://gist.github.com/239797 Circuit breaker http://gist.github.com/239798 Git repository: http://github.com/krukow/clojure-circuit-breaker The circuit breaker has a wrap function that takes another function and returns a wrapped version of that function that uses the circuit breaker. Right now there is only one circuit breaker instance, but that's easy to generalize. Feedback very welcome! /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 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
Re: "Oh, yeah, transients are fast!"
> Try with a 1.6 JVM... wow. it actually got worse than when i was using 1.5. ... so much for hallowed write-once-run-the-same-anywhere-ish of the jvm, d'oh. Clojure 1.1.0-alpha-SNAPSHOT user=> (load-file "/tmp/test.clj") #'user/vrange2 user=> (. System getProperty "java.version") "1.6.0_15" user=> (time (def v2 (vrange2 100))) "Elapsed time: 329.906 msecs" #'user/v2 user=> (time (def v2 (vrange2 100))) "Elapsed time: 888.734 msecs" #'user/v2 user=> (time (def v2 (vrange2 100))) "Elapsed time: 546.982 msecs" #'user/v2 user=> (time (def v2 (vrange2 100))) "Elapsed time: 517.969 msecs" #'user/v2 user=> (time (def v (vrange 100))) "Elapsed time: 1649.449 msecs" #'user/v user=> (time (def v (vrange 100))) --- never came back, i had to ^C^C (in emacs buffer)!! -- 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
Re: "Oh, yeah, transients are fast!"
> user=> (time (def v (vrange 100))) > --- never came back, i had to ^C^C (in emacs buffer)!! p.s. so at least the transient version never did 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 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
Re: repeatedly forcing the evaluation of a lazy seq
The sequence returned from the filter would need to be rescanned to get the nth element, but the filtering itself should only need to happen when the "next" element in the sequence is sought. For cases such as the one you describe, I think it's common to fully realize the sequence into a vector, e.g. (vec (filter ...)) to avoid rescanning. On Nov 20, 5:00 am, bOR_ wrote: > Hi all, > > Just ran into a small gotcha: I had an atom which contained a lazyseq > (e.g. (filter males world)). Later on I would be repeatedly calling > random elements from this atom, using clojure contrib rand-elt. That > was surprisingly slow. I figured out that count was the culprit. > Apparently, the lazyseq atom stayed a lazyseq atom (immutability), and > each time I called for a random element, count had to do the whole > filtering to figure out 'count'. > > Is there any way that I can get a warning printed out that would let > me know when I am doing something stupid like this? for example: > (repeatedly evaluating identical full lazy sequence @world)? -- 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
ANN: Clojuratica v2 -- Seamless Mathematica-within-Clojure!
Dear Clojurians, I am very happy to announce Clojuratica version 2. Clojuratica now offers the **syntactic** integration of Clojure and Mathematica. What does this mean? It means you can write Clojure code that looks like this: => (FactorInteger 12345) [[3 1] [5 1] [823 1]] You guessed it. FactorInteger is a Mathematica function. And that's a Clojure REPL. Symbolic math in Clojure? Syntax-unquoting to feed in Clojure data structures? Absolutely. => (Sqrt (* 9 a)) (* 3 (Power a 1/2)) => (let [x [[2 1] [1 2]]] (CholeskyDecomposition ~x)) [[(Power 2 1/2) (Power 2 -1/2)] [0 (Power 3/2 1/2)]] Note that the Clojure "matrix" (vector of vectors) is converted on the fly to a Mathematica matrix, and vice versa. Automatic conversions take place for all Clojure and Mathematica data structures. There's more. Mathematica functions are now Clojure functions. The following is a Mathematica function written in Clojure that finds the n shortest genes in the human genome. (Mathematica has some cool functions like GenomeData to try out.) => (Function [n] (Take (Sort (Map (Function [gene] [(GenomeData gene "SequenceLength") gene]) (GenomeData))) n)) # What's that ugly return value? It's a first-class Clojure function. We evaluated a Mathematica function in Clojure and got back a Clojure function which, when we call it, hands off the computation to Mathematica and returns the result: => (*1 4) [[11 "IGHD727"] [16 "IGHD411"] [16 "IGHD417"] [16 "IGHD44"]] All the power of Mathematica is now seamlessly available in Clojure. If you like, you can think of Mathematica as a particularly mature Clojure library for linear algebra, matrix decomposition, symbolic mathematics, optimization, differential equations, symbolic and numerical integration, Fourier analysis, 2D and 3D visualization, image and photo manipulation, exploratory data analysis, probability and statistics, graph theory, number theory, geodesy, and access to the Wolfram Research internet data feeds on finance, chemistry, geometry, meteorology, astronomy, protein structure, and, as we've seen, the human genome. Let's take a step back and see how it all works. Observe: Clojure and Mathematica are remarkably similar languages despite their different areas of strength. Constant-lookup arrays: Clj vectors: [1 2 3] Mma lists:{1, 2, 3} Matrices as nested arrays: Clj: [[1 0] [0 1]] Mma: {{1, 0}, {0, 1}} Function calls *always* use prefix notation: Clj: (func arg1 arg2 arg3) Mma: Func[arg1, arg2, arg3] In Mathematica, common functions do have syntactic sugar, but it always is just syntactic sugar: Clj: none Mma: 1 + 1 is just Plus[1, 1] !foo && (bar > baz) is just And[Not[foo], Greater[bar, baz]] Homoiconicity: Clj: (nth '(func arg1 arg2) 1) ==> arg1 Mma: Part[Func[arg1, arg2], 1] ==> arg1 The similarities suggest the core idea: Mathematica expressions can be written as Clojure expressions without any loss of information, and vice versa. There is perfect correspondence. Happily, Mathematica functions are PascalCase by convention. This allows the interning of Mathematica functions right into your Clojure namespace without conflict. Mma: FactorInteger[1091] Clj: (FactorInteger 1091) Mma: Function[{x}, x + 1] Clj: (Function [x] (Plus x 1)) The heart of Clojuratica is simple. Convert Clojure expressions to Mathematica expressions, evaluate them in Mathematica, and parse the result back into Clojure expressions. As you will see in the tutorial on the Clojuratica web page < http://clojuratica.weebly.com>, you are not forced to intern Mathematica functions directly into your namespace. You may, but you do not have to. The generic way to call Mathematica code is using the math macro (which you yourself define, so it need not be called "math"): => (let [x "World"] (math (StringJoin "Hello, " ~x "! This is some Mathematica code's output."))) "Hello, World! This is some Mathematica code's output." => (def hello (math (Function [x] (StringJoin "Hello, " x "! This is a Mathematica function's output." #'user/hello => (hello "World") "Hello, World! This is a Mathematica function's output." There are other features, too: * A concurrency framework for multithreaded, parallel computation. Mathematica is not designed for threads or concurrency. It has excellent support for parallel computation, but parallel evaultions are initiated from a single-threaded master kernel which blocks until all parallel evaluations return. By contrast, Clojuratica includes a concurrency framework that lets multiple Clojure threads execute Mathematica expressions without blocking others. The computations will be farmed out to as many Mathematica kernels as are parallelized on the local machine or across a cluster or grid. The computations will return asynchronously, and some threads will go about their business while others continue to wait. I have worked t
Re: ANN: Clojuratica v2 -- Seamless Mathematica-within-Clojure!
P.S. I have been told that Clojuratica works with the free Mathematica Player. I haven't tried this myself. On Fri, Nov 20, 2009 at 5:57 PM, Garth Sheldon-Coulson wrote: > Dear Clojurians, > > I am very happy to announce Clojuratica version 2. > > Clojuratica now offers the **syntactic** integration of Clojure and > Mathematica. > > What does this mean? It means you can write Clojure code that looks like > this: > > => (FactorInteger 12345) > [[3 1] [5 1] [823 1]] > > You guessed it. FactorInteger is a Mathematica function. And that's a > Clojure REPL. > > Symbolic math in Clojure? Syntax-unquoting to feed in Clojure data > structures? Absolutely. > > => (Sqrt (* 9 a)) > (* 3 (Power a 1/2)) > > => (let [x [[2 1] [1 2]]] > (CholeskyDecomposition ~x)) > [[(Power 2 1/2) (Power 2 -1/2)] [0 (Power 3/2 1/2)]] > > Note that the Clojure "matrix" (vector of vectors) is converted on the fly > to a Mathematica matrix, and vice versa. Automatic conversions take place > for all Clojure and Mathematica data structures. > > There's more. Mathematica functions are now Clojure functions. The > following is a Mathematica function written in Clojure that finds the n > shortest genes in the human genome. (Mathematica has some cool functions > like GenomeData to try out.) > > => (Function [n] > (Take >(Sort > (Map > (Function [gene] [(GenomeData gene "SequenceLength") gene]) >(GenomeData))) >n)) > # 1234 clojuratica.base.parse$parse_fn__1230$fn__1...@19fa0b5> > > What's that ugly return value? It's a first-class Clojure function. We > evaluated a Mathematica function in Clojure and got back a Clojure function > which, when we call it, hands off the computation to Mathematica and returns > the result: > > => (*1 4) > [[11 "IGHD727"] [16 "IGHD411"] [16 "IGHD417"] [16 "IGHD44"]] > > All the power of Mathematica is now seamlessly available in Clojure. If you > like, you can think of Mathematica as a particularly mature Clojure library > for linear algebra, matrix decomposition, symbolic mathematics, > optimization, differential equations, symbolic and numerical integration, > Fourier analysis, 2D and 3D visualization, image and photo manipulation, > exploratory data analysis, probability and statistics, graph theory, number > theory, geodesy, and access to the Wolfram Research internet data feeds on > finance, chemistry, geometry, meteorology, astronomy, protein structure, > and, as we've seen, the human genome. > > Let's take a step back and see how it all works. > > Observe: Clojure and Mathematica are remarkably similar languages despite > their different areas of strength. > > Constant-lookup arrays: > > Clj vectors: [1 2 3] > Mma lists:{1, 2, 3} > > Matrices as nested arrays: > > Clj: [[1 0] [0 1]] > Mma: {{1, 0}, {0, 1}} > > Function calls *always* use prefix notation: > > Clj: (func arg1 arg2 arg3) > Mma: Func[arg1, arg2, arg3] > > In Mathematica, common functions do have syntactic sugar, but it always is > just syntactic sugar: > > Clj: none > Mma: 1 + 1 is just Plus[1, 1] > !foo && (bar > baz) is just And[Not[foo], Greater[bar, baz]] > > Homoiconicity: > > Clj: (nth '(func arg1 arg2) 1) ==> arg1 > Mma: Part[Func[arg1, arg2], 1] ==> arg1 > > The similarities suggest the core idea: Mathematica expressions can be > written as Clojure expressions without any loss of information, and vice > versa. There is perfect correspondence. Happily, Mathematica functions are > PascalCase by convention. This allows the interning of Mathematica functions > right into your Clojure namespace without conflict. > > Mma: FactorInteger[1091] > Clj: (FactorInteger 1091) > > Mma: Function[{x}, x + 1] > Clj: (Function [x] (Plus x 1)) > > The heart of Clojuratica is simple. Convert Clojure expressions to > Mathematica expressions, evaluate them in Mathematica, and parse the result > back into Clojure expressions. > > As you will see in the tutorial on the Clojuratica web page < > http://clojuratica.weebly.com>, you are not forced to intern Mathematica > functions directly into your namespace. You may, but you do not have to. The > generic way to call Mathematica code is using the math macro (which you > yourself define, so it need not be called "math"): > > => (let [x "World"] > (math (StringJoin "Hello, " ~x "! This is some Mathematica code's > output."))) > "Hello, World! This is some Mathematica code's output." > > => (def hello > (math >(Function [x] > (StringJoin "Hello, " x "! This is a Mathematica function's > output." > #'user/hello > > => (hello "World") > "Hello, World! This is a Mathematica function's output." > > There are other features, too: > > * A concurrency framework for multithreaded, parallel computation. > Mathematica is not designed for threads or concurrency. It has excellent > support for parallel computation, but parallel evaultions are initiated from > a single-threaded master kernel whic
Weird Java Interop Behaviour
Hi. I can't find the answer to this anywhere. (It seems it should be posted somewhere already ...) This works: (. System getProperty "java.version") -> "1.6.0_15" This does not work: (. (identity System) getProperty "java.version") -> java.lang.IllegalArgumentException: No matching method found: getProperty for class java.lang.Class (NO_SOURCE_FILE:0) BUT (identity System) returns System as we see here: (.equals (identity System) System) -> true Why does (. System getProperty "java.version") work when (. (identity System) getProperty "java.version") does not work, given that (identity System) should be the same as System ? Thanks for any insight here! Matt -- 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
Re: Weird Java Interop Behaviour
It's the . special form that makes the difference. In (. System (getProperty)), the dot interprets System as a class and looks for a static method (at read/compile time). With (identity System), System resolves to a value, a Class object, returned by identity, then your outside dot looks for a getProperty instance method on that object(fallback to reflection, which fails) - it's like writing System.class.getProperty in java. There is no syntax for clojure to lookup a static method on a dynamically resolved class object because that is inherently reflection - dot is not about reflection, though it will do it as a last resort. Hope that helps. -Mike -- 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
Re: Weird Java Interop Behaviour
Matt Brown wrote: > Why does (. System getProperty "java.version") work when > (. (identity System) getProperty "java.version") does not work, given > that > (identity System) should be the same as System ? It's because the . special form treats class names specially. In Java there's unfortunately a difference between instances of the java.lang.Class object and the class itself. So: Clojure: (. System getProperty "java.version") Java: System.getProperty("java.version"); While: Clojure: (. (identity System) getProperty "java.version") ; error! Java: System.class.getProperty("java.version"); // error! But if you call a method that exists on a java.lang.Class object it's okay: (. (identity System) getMethods) It's preferred style in Clojure to use this form to access static methods and fields as it prevents this sort of confusion: (System/getProperty "java.version") -- 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
Re: tree-shaking a jarred Clojure app?
On Fri, Nov 20, 2009 at 2:28 PM, Richard Newman wrote: > > But I should be able to know, through class inspection, whether my > > 'main' program depends on a class which uses, say, the clojure.zip > > namespace, and decide whether or not to include it. Or so I am > > wondering. > > There are impediments to that, too -- your namespace might require > another, and so on, and your namespace can refer to symbols further > down the chain without itself including the necessary `require` form. > There's the possibility of a macro expanding to a nonobvious require or use form. Also of "eval" being used. Even in the Java world, class names that get dynamically loaded sometimes come from XML files rather than being in the Java source anywhere. But there is an alternative to static analysis, at least in theory. One could, in principle, run one's new app or servlet or whatever on a JVM with a modified class-loading infrastructure set up to log all loaded classes, then put it through its paces in typical usage scenarios and the anticipated atypical situations. If you have good test coverage, you could simply run the test suite with class-loading logging enabled, and make any appropriate substitutions of real classes (and their dependencies) for mock-object classes. Or if the tests don't use any mock objects in really obscure cases whose real counterparts aren't also used in the typical situation, just log a normal run and a run through the test suite and dump all the mock object classes and test-harness classes. Sun probably provides debug tools that can log classes loaded on a JVM session, so everything needed for this is in theory available off-the-shelf. End product: a list of every used class. At least in theory. -- 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
Re: "Oh, yeah, transients are fast!"
On Fri, Nov 20, 2009 at 5:16 PM, Raoul Duke wrote: > > Try with a 1.6 JVM... > > wow. it actually got worse than when i was using 1.5. ... so much for > hallowed write-once-run-the-same-anywhere-ish of the jvm, d'oh. > > Clojure 1.1.0-alpha-SNAPSHOT > user=> (load-file "/tmp/test.clj") > #'user/vrange2 > user=> (. System getProperty "java.version") > "1.6.0_15" > user=> (time (def v2 (vrange2 100))) > "Elapsed time: 329.906 msecs" > #'user/v2 > user=> (time (def v2 (vrange2 100))) > "Elapsed time: 888.734 msecs" > #'user/v2 > user=> (time (def v2 (vrange2 100))) > "Elapsed time: 546.982 msecs" > #'user/v2 > user=> (time (def v2 (vrange2 100))) > "Elapsed time: 517.969 msecs" > #'user/v2 > user=> (time (def v (vrange 100))) > "Elapsed time: 1649.449 msecs" > #'user/v > user=> (time (def v (vrange 100))) > --- never came back, i had to ^C^C (in emacs buffer)!! You've got some kind of system problem confounding your results, I'll bet. It got slower? One test actually hung? My suspicion, of course, lies with the emacs environment you've just confessed to using. Half the traffic on this list at times is from people having problems with configuring either emacs or vi to work well with Clojure. Try it in a modern IDE, or from the command line, and see if the problem goes away. If it does, then you know the likely culprit and it isn't Clojure's transients. :) -- 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
Clojure Scoping Rules
Even though I have used Clojure, I hadn't looked at the scoping rules in detail. I am getting more confused as I read the documentations. I made a small test to try out the scoping resolutions and am apalled at the complexity. Could somebody explain the intent and various rules that Clojure uses? (def x 1) (defn dummy-fn2[] (+ x 1)) (defn dummy-fn[] (println "entering function: " x) (let [x 100] (println "after let: " x) (let [x (dummy-fn2)] (println "after let and dummy2: " x) (binding [x 100] (println "after binding: " x) (let [x (dummy-fn2)] (println "after binding and dummy2: " x)) 1:2 foo=> (dummy-fn) entering function: 1 after let: 100 after let and dummy2: 2 after binding: 2 after binding and dummy2: 101 nil -- 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
Re: Clojure Scoping Rules
Conceptually, the best way to think about it is that your binding sets the global x to 100 and restores the global x to 1 when exiting the scope of the binding construct. It has no effect on your local x. Dynamic binding is confusing, and should be used with care. If you stick with the lexical scoping of function closures and lets, things should behave the way you expect. --Mark On Fri, Nov 20, 2009 at 7:40 PM, kunjaan wrote: > Even though I have used Clojure, I hadn't looked at the scoping rules > in detail. I am getting more confused as I read the documentations. I > made a small test to try out the scoping resolutions and am apalled at > the complexity. Could somebody explain the intent and various rules > that Clojure uses? > > (def x 1) > > (defn dummy-fn2[] > (+ x 1)) > > (defn dummy-fn[] > (println "entering function: " x) > (let [x 100] > (println "after let: " x) > (let [x (dummy-fn2)] > (println "after let and dummy2: " x) > (binding [x 100] > (println "after binding: " x) > (let [x (dummy-fn2)] > (println "after binding and dummy2: " x)) > > 1:2 foo=> (dummy-fn) > entering function: 1 > after let: 100 > after let and dummy2: 2 > after binding: 2 > after binding and dummy2: 101 > nil > > -- > 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 -- 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
Re: Clojure Scoping Rules
On Fri, Nov 20, 2009 at 8:02 PM, Mark Engelberg wrote: > Dynamic binding is confusing, and should be used with care. Elaborating on my previous point: it's especially confusing because dynamic binding interacts poorly with lazy data structures, which is predominantly what you deal with in Clojure. If your lazy data structure depends on something that is dynamically bound using binding, there is a good chance it won't get evaluated until after you exit the scope of the binding and the global variable is restored to its earlier state, so your lazy data structure ends up not using the value that was set with binding. It can get messy fast. There were a couple times I used dynamic binding, and I was really excited about it. I had never used a language with a dynamic binding construct, and it seemed like a perfect fit for what I was doing. I was threading a couple of values through a bunch of mutually recursive functions that generated a tree. The values I was threading controlled certain aspects of the tree generation. I realized that by making these generation parameters global values, and just wrapping binding to set the parameters around the call to my tree generator, I could avoid all these extra inputs on a whole slew of functions that were just passing these parameters around so they'd be available in the functions that really needed them. But my tree generator used laziness in some non-obvious places, and it took me a long time to notice that when I didn't fully evaluate the tree right away, I was getting very different results. It was hard to track down the problem, and ultimately I had to go back to threading all the parameters through the functions explicitly. The experience really turned me off of dynamic binding in Clojure, since it has such a strong laziness focus. Which reminds me, every once in a while I see people talking about this here, and brainstorming up some alternatives to binding that might interact better with lazy data structures. Has there been any real progress on this, or has every proposed solution been equally problematic? -- 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
Monad problems: finding an m-zero
I'm writing a maybe/state monad using clojure.contrib.monads. I've gotten by fine with using just (state-t maybe-m), but now I need different behavior: I need a monad that behaves precisely like (state-t maybe-m), except that when a monadic value mv is called on a state s and fails, (mv s) returns [::failure s] *instead of nil* (as maybe-m normally does). This is the difference. Now I'm basically done, except I can't figure out a value of m-zero that fulfills the required axioms: - (m-bind m-zero f) produces m-zero - (m-bind mv (fn [x] m-zero)) produces m-zero This is what I have so far: (defmonad parser-m "The monad that FnParse uses." [m-zero (fn [state] [::failure state]) m-result (fn m-result-parser [product] (fn [state] [product state])) m-bind (fn m-bind-parser [rule product-fn] (fn [state] (let [result (rule state)] (if (failure? result) result (let [[product new-state] result] ((product-fn product) new-state)) m-plus (fn m-plus-parser [& rules] (fn [state] (or (first (drop-while failure? (map #(% state) rules))) (m-zero state]) The first axiom is fulfilled: user=> (def a (m-bind m-zero (constantly [5 [2 3]]))) #'user/a user=> (a [0 1]) [:user/failure [0 1]] user=> (m-zero [0 1]) [:user/failure [0 1]] But the second is not: user=> (def b (m-bind (constantly [:x [1 2]]) m-zero)) #'user/b user=> (b [0 1]) And no matter what I do, I can't fulfill that second axiom. Has anyone created this type of monad before? It seems like it should be a common pattern: exactly like (state-t maybe-m), only failures are vector pairs too. -- 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