Re: How to model a rectangle?
Looks interesting, thanks! On Thu, Mar 5, 2015 at 4:43 PM, Leon Grapenthin grapenthinl...@gmail.com wrote: (defn rect2 [x y width height] (let [lr [(+ width x) (+ width y)]] (reify Rect (upper-left [_] [x y]) (lower-right [_] lr) (area [_] (* width height) Just a quick remark: In JavaScript I purposefully did not use `width` and `height` for calculating area. That way the garbage collector can release them, making objects smaller. -- 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 unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
How to model a rectangle?
Disclaimer: I’ve never done *any* Clojure programming, but I’m curious. Here’s how I may model an on-screen rectangle in JavaScript, a classless object oriented language: let createRectangle = function (x, y, width, height) { return { get upperLeft() { return [x, y]; }, get lowerRight() { return [x + width, y + height]; }, get area() { return width * height; } }; }; let r = createRectangle(0, 0, 50, 20); let s = createRectangle(10, 20, 40, 5); console.log(r.upperLeft, r.lowerRight, r.area); console.log(s.upperLeft, s.lowerRight, s.area); Now I run the profiler. I discover that in the inner loop of my program there are lots of calls needing the upper left and the lower right coordinates. So I change the inner workings of the object to store these instead: let createRectangle = function (x, y, width, height) { let upperLeft = [x, y], lowerRight = [x + width, y + height]; return { get upperLeft() { return upperLeft; }, get lowerRight() { return lowerRight; }, get area() { return (lowerRight[0] - upperLeft[0]) * (lowerRight[1] - upperLeft[1]); } }; }; Boom: Now the program is twice as fast, and - what gives me great comfort - I know that this change breaks nothing. I only had to edit the code in *one* module. I didn’t need to think too much about efficiency of data structures in the beginning. I could just start going, then optimize in the end. *Can I program in a similar way using Clojure?* -- 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 unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: edn
Michael Fogus mefo...@gmail.com writes: Data formats do not exist in a vacuum. They are parsed by languages. Some may have a fine-grained distinction between lists, arrays/vectors and sets and some may not. The concern I have is for someone wanting to define a format atop EDN -- or, to put it differently, to define a schema for it. If we want to define a structure to be represented in EDN such as a list of a person's favorite colors, on what basis would the schema author choose between list and vector notation? Is there a higher-level abstract type that he specify and require that a conforming processor accept either a list or vector literal? Even if he could mandate that, say, the favorite color list is of type sequence -- listed in descending order of preference -- then an author creating the EDN to represent such a person again has to make a choice between a list and a vector, again without a clear basis for his decision. As an appeal to prior art, Rivest's S-Expressions Internet-Draft¹ used only a single list structure, though it does define three different encodings for that structure. Footnotes: ¹ http://people.csail.mit.edu/rivest/Sexp.txt -- Steven E. Harris -- 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: edn
Ben Smith-Mannschott bsmith.o...@gmail.com writes: I follow forbidding -4bar since that means potentially unbounded look-ahead to distinguish numbers from non-numbers. Presumably forbidding .4bar is for the same reason, though .01 doesn't appear to be a valid numeric literal. (Numeric literals all start with a digit.) Common Lisp provides useful precedent with its notion of potential numbers¹. If we stretch the analogy of namespace syntax to Common Lisp package syntax, clause 3 in HyperSpec section 2.3.1.1² -- Potential Numbers as Tokens -- is relevant to your cases above. ,[ §2.3.1.1 ] | 3. The token begins with a digit, sign, decimal point, or extension |character, but not a package marker. The syntax involving a leading |package marker followed by a potential number is not |well-defined. The consequences of the use of notation such as :1, |:1/2, and :2^3 in a position where an expression appropriate for read |is expected are unspecified. ` Well, I suppose that's precluding using the package marker without an actual package name ahead of it, like using '/' without a namespace name before it. In any case, Common Lisp parses both -4bar and .4bar as symbols: , | * (loop for s in '(-4bar .4bar) collect (type-of (read-from-string s))) | (SYMBOL SYMBOL) ` Footnotes: ¹ http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_p.htm#potential_number ² http://www.lispworks.com/documentation/HyperSpec/Body/02_caa.htm -- Steven E. Harris -- 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: edn
Armando Blancas abm221...@gmail.com writes: I'd say on the basis of convenience, since we get to serialize and deserialize for free (o with customizations), and for most cases the author on both ends is likely to be the same person or team. I find that to be a specious defense. If we expect the same author to be on both ends of the wire or reading the files he wrote himself, why take interest in such a specified format anyway? For other languages, producers don't work any harder either way, and consumers are free to interpret both the schema and data as they need. It sounds like you've ignored the thrust of my concern rather than settling it. sexp's only have a list notation because that's all lisp had, and even then, some people got it all for free. That tail did not wag that dog. -- Steven E. Harris -- 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: Tail-recursive lazy sequence construction by appending to the end of accumulator problem.
Alexander Semenov bohtva...@gmail.com writes: The second lazy approach still needs to traverse all the sequence recursively, why doesn't it cause stack overflow? You might find my answer to the StackOverflow question Thinking in Lazy Sequences useful here: http://stackoverflow.com/a/2214049/31818 Note that I wrote it about a year and a half ago. I hope the references to the Java classes are still correct. -- Steven E. Harris -- 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: Leiningen2 + lein-midje + lazytest question
On 06/12/2012 12:05 PM, Phil Hagelberg wrote: On Mon, Jun 11, 2012 at 1:46 PM, Phil Hagelbergp...@hagelb.org wrote: On Mon, Jun 11, 2012 at 12:52 PM, Cédric Pineaucedric.pin...@gmail.com wrote: My question is with the lazy-test dependency. Do I really have to put it as a project dependency ? It doesn't seem to be on the lein-midje path when puting it in the dev-dependencies.. If it's required for lein-midje then lein-midje should add it to your dependencies without you needing to do anything. I should clarify that I know nothing about lein-midje in particular; I'm just commenting on what the proper behaviour of plugins should be. -Phil The issue here is that Midje and lein-midje don't need Lazytest for normal operation, only for the --lazytest support. What would be the proper way to specify that dependency without requiring that everyone that uses Midje also carry around Lazytest? I know the answer would probably be needing a lein-midje-lazytest artifact that adds that support, but that seems overkill. -- 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
A question of technique: clojure-hadoop's patching of methods
Recently I was studying Stuart Sierra's clojure-hadoop project¹, and there saw a technique that I'd like to discuss. There's a Java class generated whose method definitions get patched based on a provided configuration, and I'd like to understand the scope of this patching and why the technique's effects are acceptable for this project. The namespace clojure-hadoop.job² uses the macro clojure-hadoop.gen/gen-job-classes³ to, well, generate a few Java classes. Later, in the job/configure-functions functionº, we see use of the alter-var-root function to change the functions associated with the Java methods Mapper#map() (here, mapper-map) and Reducer#reduce() (here, reducer-reduce). Now to my questions. This mutation of the class-method-to-Clojure-function binding appears to be global. Will it impact /all/ instances of the generated classes within this Clojure process? If this impact is global, is it the case that this software never needs to accommodate instances of these generated classes with different configurations? In other words, the job-related classes wind up getting mutated to conform to one particular configuration. That means that a given run of the program can't handle more than one configuration at a time. Is that acceptable here because Hadoop is only going to load these classes for use with a single configuration? The patching looks like an optimization to avoid associating functions with each Mapper or Reducer /instance/, so that it avoids that kind of which-function-should-I-call-now lookup on each invocation. Is that a correct interpretation of the design rationale? Footnotes: ¹ https://github.com/stuartsierra/clojure-hadoop ² https://github.com/stuartsierra/clojure-hadoop/blob/master/src/main/clojure/clojure_hadoop/job.clj ³ https://github.com/stuartsierra/clojure-hadoop/blob/master/src/main/clojure/clojure_hadoop/gen.clj#L5 º https://github.com/stuartsierra/clojure-hadoop/blob/master/src/main/clojure/clojure_hadoop/job.clj#L31 -- Steven E. Harris -- 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 question of technique: clojure-hadoop's patching of methods
Stuart Sierra the.stuart.sie...@gmail.com writes: I haven't looked at that code in a long time, but the answer is yes. Each Hadoop Job runs in its own JVM process. Thank you. That makes sense, then. Just to nail it home, though, do you agree that this patching technique is generally /not/ tenable in programs that need to use several instances of a such a class, each with different configuration? I think we'd either need another layer of indirection in the method dispatch, or instead use a class-generating macro that demands that configuration at macroexpansion time, creating a distinct class for each. -- Steven E. Harris -- 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: defmulti and defmethods in separate namespaces without circular references?
I use a lot of multimethods with my framework, Ciste[0] and it can work, the only thing is you have to be very careful about what you put where, and it helps to have a lot of namespaces. What I do is try to keep all of my defmulti's in one namespace and have only defmethod's in another namespace. Originally, I had one master namespace that required all of the defmethod namespaces (my routes namespace) and then all my action namespaces only require the defmulti namespaces. I've since then moved on to use the 'definitializer' functionality of Ciste to require those defmethod namespaces after all of the other namespaces have been required. I'm not saying it's the best coding style, but it works for me and my applications. Be prepared to move functions around a lot to always stay one step ahead of the dreaded cyclic dependency horror. 0: https://github.com/duck1123/ciste On 03/02/2012 10:55 AM, Cymen Vig wrote: On Friday, March 2, 2012 7:03:10 AM UTC-6, tim.visher wrote: I will not in any way claim to know how or why this works. I'm just starting to use multimethods myself, but I'll give you my set up that appears to be working at the moment. I have a namespace: (ns store.store) (defmulti serialize method) (defmulti slurp method) in store.clj I have 1 implementation: (ns store.file-system [:use [store.store]] …) (def base ) (defmethod serialize :file-system [_ file-name contents] (fs-utils/write-to contents (str base / file-name))) (defmethod slurp :file-system [_ file-name] (clojure.core/slurp (str base / file-name))) I then use this from another namespace, requiring store.store and store.store.file-system: (ns library [:require [wallpaper-manager-core.store.file-system :as store-file-system]] [:require [wallpaper-manager-core.store.store :as store]]) (binding [store-file-system/base (fs/home)] (def library (ref (read-library) :validator library-validator))) (defn serialize-library [library] (store/serialize :file-system library.clj library)) And this all seems to work fine for me. Maybe someone else can explain why it does for me and doesn't for you. Maybe it has something to do with `use` vs. `require`? This does indeed work for me. What I was trying to do was avoid was having to do this part: ... [:require [wallpaper-manager-core.store.store :as store]]) As each time I add a defmethod implementation of my defmulti I'd have to add another require. But maybe that isn't such a bad thing so I'll go with this approach. I prefer it over having a super parent (*) namespace unless i needed that super parent in multiple places. * by super parent I mean a namespace that is only used to include the namespaces that contain the defmulti and defmethods Thanks, Cymen -- 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: Bret Victor - Inventing on Principle
On 02/24/2012 02:42 PM, Cedric Greevey wrote: On Fri, Feb 24, 2012 at 2:25 PM, Jay Fields j...@jayfields.com wrote: On Fri, Feb 24, 2012 at 2:12 PM, Cedric Greevey cgree...@gmail.com wrote: On Fri, Feb 24, 2012 at 2:06 PM, gaz jones gareth.e.jo...@gmail.com wrote: Are you Ken Wesson with a new account? Who? Wait. Surely you don't think that it's not possible for more than one person to prefer text to video as a way of disseminating verbal information over the internet, given all of text's advantages in such areas as bandwidth, cost, and tool support? Surely it's possible that you've never heard of Ken Wesson, he disappeared right before you joined, you respond to emails in the same manner, you share the same opinions. Seems legit, Ken. OK. I googled the group archives. Seems there was a Ken Wesson active on the list for a while, but he disappeared a couple of months before I joined. I'm not sure why people think I might be him. Ken Wesson was noted for having strong opinions as was a noted hater of videos where text will do. https://groups.google.com/d/msg/clojure/0kCwGrFU5zs/NGclkY46fvEJ -- 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: Controlling the test environment
-BEGIN PGP SIGNED MESSAGE- Hash: SHA1 On 01/15/2012 06:18 PM, Matt Stump wrote: Is there a way to set different values for global vars when running tests as opposed to the development or production environment? I need to control which database my tests for a noir project connect to. Ideally I would like to do something like the following: for production and development, if an environment variable is set connect to the database server at the specified URL, if not then fall back to localhost. For test start up an embedded server, and connect. After the test is done, rollback the global var to the previous value and resume connecting to the server on localhost or at the location specified by the environment variable. I could create some fixture with-test-database that modifies a global var, but that seems a little hackish. How are other people solving this problem? Is there something similar pre-baked into noir, clojure.test or midje? I wrote support for configuration with different environments into Ciste.[1] You create a config.clj file at the root of your application that contains a map with each of the keys being a keyword naming the environment and the value is a map for all the config options. You can then use set-environment! or with-environment to set the current environment. You can then wrap some code in definitializer. That code will be run whenever the environment changes. I set the environment when my application runs and then wrap all my tests in (with-environment :test ) The config namespace should be isolated enough that you could use it without involving any of the other features. 1: https://github.com/duck1123/ciste/ -BEGIN PGP SIGNATURE- Version: GnuPG v1.4.11 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/ iEYEARECAAYFAk8ZoO0ACgkQWorbjR01Cx59cACffeQeffgR0zgtqt5FXGaQy9gx zz8An2pMclSd+qA8dxc8XMPB+gMbhNjR =XbSs -END PGP SIGNATURE- -- 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: repl output for list seems inconsistent and a holdover from yesteryear
On Oct 26, 2011 7:15 PM, Stuart Halloway stuart.hallo...@gmail.com wrote: checking out the Try Clojure: if you type the following, you get output that matches what you typed in every case except for lists. Vectors: -- [1 2 3 4] [1 2 3 4] Maps: -- {:foo bar 3 4} {:foo bar 3 4} Lists: -- '(1 2 3 4) (1 2 3 4) - *INCONSISTENT* why not render this as '(1 2 3 4) ... this would make much more sense to newbies. Sets: -- #{1 2 3 4} #{1 2 3 4} This is an interesting question. Consistency is important, but consistency with what? Your mental model for what happens at the REPL needs to keep the R, E, and P steps clearly separate. Working backward: the P (Print) prints things in a way that they can be read back, where possible: (read-string [1 2 3 4]) = [1 2 3 4] (read-string (1 2 3 4)) = (1 2 3 4) (read-string #{1 2 3 4}) = #{1 2 3 4} (read-string {1 2 3 4}) = {1 2, 3 4} If the P part of the REPL put a tick in front of lists, they would not read back correctly: (read-string '(1 2 3 4)) = (quote (1 2 3 4)) INCONSISTENT I see the problem that token ' is already taken to be short hand for quote so to be truly consistent, I might be compelled to argue that (read-string '(1 2 3 4)) should, seeing some hypothetical list start multi-char token '( just like set-start is #{ , be: = '(1 2 3 4). You'd need two single quotes: ''(1 2 3 4) to get quote '(1 2 3 4) ... Wheras (1 2 3 4) means call 1 with ... I'll have to reread the explanation about the repl phases, but maybe I'm wondering if things don't have to be quoted if lists had the syntax I describe, and requests for function invocation had a simple paren. Then you are not saying, treat this as data, do not eval. You are just saying, see my single quote paren token? That's for lists. Maybe it would be clearer if I proposed some other, lesser-used chars, like %(1 2 3 4) or even 1 2 3 4. That is, I'm not so much saying, this needs to be treated as data and not eval'd as I am simply saying, this is the 'list' data structure as opposed to some other. Now, if you ever need to read in a program and treat it like data, well, what structure would you like to put it in? A list? A vector? A string? This is, indeed, where I am fuzzy on lisps, but it seems like you parse it as desired and put it where/how you like it. Why is there an assumption that code as data means code as lists? Or is there? Now to the R (Reader) part. If, as you suggest, the tick were part of the reader syntax for lists, you could fix the inconsistency above: ;; hypothetical Clojure with '(...) list literals (read-string ' '(1 2 3 4)) = (1 2 3 4) Finally, consider the poor E (Evaluator) in this scenario. The evaluator must (1) evaluate lists except (2) *not* evaluate lists that are protected by quote. But now that the tick is part of the syntax you have two challenges: (1) Since the tick no longer prevents evaluation, you have to spell out the quote (and still use the tick!) ;; hypothetical literal list (quote '(1 2 3)) (2) Since the tick is required as part of list syntax, your programs have to be written with ticks everywhere like this: '(defn hello-world [] '(println hello) You have to understand R, E and P as separate steps to understand the REPL. As a side note, it is worth mentioning that the REPL is composed of three simple parts, and that interactive shells that do not have this factoring are much less useful. Imagine if your language didn't separate reading and evaluating. You would need JSON or something to serialize data... Stu Stuart Halloway Clojure/core http://clojure.com -- 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: repl output for list seems inconsistent and a holdover from yesteryear
You can also use the list function if you don't care about syntactic sugar, and it seems. Like it should look like this: = (list 1 2 3 4) '(1 2 3 4) or 1 2 3 4 -- although i'd use that for vectors and use [] for lists. Wouldn't that be cool? I imagine (set 1 2 3 4) prints as #{1 2 3 4} On Oct 27, 2011 5:46 PM, Nicolas bousque...@gmail.com wrote: Hi! Well [1 2 3] is just a syntaxic sugar for (vector 1 2 3): =(vector 1 2 3) [1 2 3] When you enter a vector in the repl, it is evaluted to itself. Here an example that show it: =[1 2 (+ 1 2)] [1 2 3] And you can use the vector function for the same result: =(vector 1 2 (+ 1 2)) [1 2 3] The quote prevent evaluation but this is not specific to lists: ='[1 2 (+ 1 2)] [1 2 (+ 1 2)] The way to make function calls in lisp (and in clojure) is to consider the first element of the list to be the function, and the next one to be the argument of the function. This what happen when you perform say an addition (+ 1 2) is a call to the add function with 2 parameters. But this mean that you can't define a list (data structure) just by writing it, because it will be evaluated. To prevent this, maybe the best solution is to use the list function, that return a list with its arguments. =(list 1 2 3) (1 2 3) You see the consistency here. As vectors are contructed with vector function. Notice calling the list function is very different that using a quote: =(list 1 2 (+ 1 2)) (1 2 3) ='(1 2 (+ 1 2)) (1 2 (+ 1 2)) This mean that you might not want to use quote everywhere just to say 'here is a list data structure'. The preference for vectors as data structure when possible is to make code more lisible. Using a list is just adding more parens, in a language with lot of parens. Doesn't help the reading. Using syntaxic sugar for vector, on the contrary help the reading. On 27 oct, 01:08, e evier...@gmail.com wrote: not necessarily. [1 2 3] is a vector that is not evaluated. Since there is no overload with things that are, there's no need for a special mark. '(1 2 3) is currently a way of say, don't evaluate this list, but it could have been: '(1 2 3) is a list that is not evaluated. No loss of generality. it's a special type of list. One that's not evaluated. as opposed to a special indicator to the repl. On Wed, Oct 26, 2011 at 6:09 PM, Mark Rathwell mark.rathw...@gmail.com wrote: The point to think about here is that functions are also lists, the same as your list of integers. The difference is that one is evaluated, the other is not. That is what the quote is saying: don't evaluate me. The quote is not actually a part of the list. It's just the way you tell the reader not to evaluate the list that follows. So the question is should all unevaluated forms be preceded with a quote in the repl output? To me that would be more confusing. On Wed, Oct 26, 2011 at 5:34 PM, e evier...@gmail.com wrote: long long time since I last looked a clojure, but I've never lost interest and I'm trying to find the time again. for the short version see *INCONSISTENT*, in the example at the end. I know what the answer will be here. Something like you will get used to it. or it's not important. or no one hardly uses lists anymore, anyway, since vectors are not purely contiguous. But, if you can make things better and it's easy, then why not? So here's the deal: I still think the following is only inconsistent because that's how it was in older lisps. Specifically, lists had to be quoted so the first argument wouldn't be called as a function. I asked long ago (here and in person) why, then regular functions couldn't require the quote so the paren could be reserved for the list data structure, and Rich answered that it'd simply be a pain to have to quote every function call. Well, my mind moves slowly. I'm just now realizing to ask, Ok, then how about making the list really be defined using the single quote as part of it just like sets include the sharp to distinguish them from maps?. That's a much simpler explanation than saying, you have to escape them, etc, etc. I realize this is a small matter since all I am talking about is how lists are represented as text. checking out the Try Clojure: if you type the following, you get output that matches what you typed in every case except for lists. Vectors: -- [1 2 3 4] [1 2 3 4] Maps: -- {:foo bar 3 4} {:foo bar 3 4} Lists: -- '(1 2 3 4) (1 2 3 4) - *INCONSISTENT* why not render this as '(1 2 3 4) ... this would make much more sense to newbies. Sets: -- #{1 2 3 4} #{1 2 3 4} -- 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
Re: repl output for list seems inconsistent and a holdover from yesteryear
On Thu, Oct 27, 2011 at 7:42 PM, Stephen C. Gilardi squee...@mac.comwrote: On Oct 26, 2011, at 7:08 PM, e wrote: [1 2 3] is a vector that is not evaluated. Since there is no overload with things that are, there's no need for a special mark. If you type [1 2 3] into the REPL it is evaluated. The E part of the REPL always runs. Some expressions evaluate to themselves. In this case each number evaluates to itself and the vector evaluates to itself: user [1 2 3] [1 2 3] If you have an expression as one of the items in the vector, it will be evaluated: user [1 (+ 1 1) 3] [1 2 3] Putting a quote out front suppresses all evaluation: user '[1 (+ 1 1) 3] [1 (+ 1 1) 3] '(1 2 3) is currently a way of say, don't evaluate this list, More completely it says, don't evaluate the entire expression that follows including any and all sub-expressions but it could have been: '(1 2 3) is a list that is not evaluated. No loss of generality. it's a special type of list. One that's not evaluated. as opposed to a special indicator to the repl. Current behavior: user '(1 (+ 1 1) 3) (1 (+ 1 1) 3) The behavior you propose: user '(1 (+ 1 1) 3) (1 2 3) ^ excellent explanation right above. +1 Currently 'x is equivalent to (quote x) for all values of x. With the syntax you propose that's no longer true. clojure.main/repl allows you to replace the evaluator with any function of one argument. If you bring up a repl with, say, lein repl, you can start a nested repl with identity as the evaluator and see how things are read (which can be interesting): % lein repl REPL started; server listening on localhost port 46512 user= (clojure.main/repl :eval identity) user= (+ 1 2) (+ 1 2) user= '(+ 1 2) (quote (+ 1 2)) user= [1 2 3] [1 2 3] user= [1 (+ 1 1) 3] [1 (+ 1 1) 3] user= 'x (quote x) user= x x user= '[1 (+ 1 1) 3] (quote [1 (+ 1 1) 3]) user= #(+ 3 %) (fn* [p1__161#] (+ 3 p1__161#)) --Steve -- 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: repl output for list seems inconsistent and a holdover from yesteryear
On Thu, Oct 27, 2011 at 8:26 PM, Mark Rathwell mark.rathw...@gmail.comwrote: Maybe it would be clearer if I proposed some other, lesser-used chars, like %(1 2 3 4) or even 1 2 3 4. That is, I'm not so much saying, this needs to be treated as data and not eval'd as I am simply saying, this is the 'list' data structure as opposed to some other. A list data structure and a list code structure are the same. why wasn't vector chosen for code? The only difference is that the programmer decides when one should not be evaluated. By creating separate syntax for a list data structure you are in essence creating a different structure for lists of data than lists of code, and you no longer have a straightforwardly homoiconic language. This seems like a hugely important thing for me to grock, but it is easier to grock in languages that, say, ONLY have lists. Otherwise it seems like code is arbitrarily ONE of the data structures and, therefore is NOT homoiconic with respect to any other data structure. Why is there an assumption that code as data means code as lists? Or is there? This is the key to everything. Code is data yes, fine. but data doesn't always mean list in *my* mind. But I'm starting to get that it was chosen to be the same thing in lisps. , data is code, they are the same structure. By treating a list of data (integers for example) differently than a list of code (function and args), you create a situation where code and data are no longer the same thing. no. code and lists are no longer the same thing. I see data as a generic concept . . .a superset, not a different set. code could be data that I haven't picked a data structure for, yet. That trait is a fundamental trait of lisps, and makes things like macros much simpler. I suspected this, too. ok. You don't have to call the structure a list, you can call it something else if you prefer, but whatever it is called, it must be the same structure that defines code and defines data. But, again, there are plenty of structures that define data differently then that which was chosen for code. So why not just have a code structure. Again, it already seems broken with respect to other structures. Here's some data. It's a vector. Here's *more* data. It's a chunk of code. Ah but it was arbitrarily decided (more from history and evolution) that *that* data is a list. Broken. On Thu, Oct 27, 2011 at 6:58 PM, e evier...@gmail.com wrote: On Oct 26, 2011 7:15 PM, Stuart Halloway stuart.hallo...@gmail.com wrote: checking out the Try Clojure: if you type the following, you get output that matches what you typed in every case except for lists. Vectors: -- [1 2 3 4] [1 2 3 4] Maps: -- {:foo bar 3 4} {:foo bar 3 4} Lists: -- '(1 2 3 4) (1 2 3 4) - *INCONSISTENT* why not render this as '(1 2 3 4) ... this would make much more sense to newbies. Sets: -- #{1 2 3 4} #{1 2 3 4} This is an interesting question. Consistency is important, but consistency with what? Your mental model for what happens at the REPL needs to keep the R, E, and P steps clearly separate. Working backward: the P (Print) prints things in a way that they can be read back, where possible: (read-string [1 2 3 4]) = [1 2 3 4] (read-string (1 2 3 4)) = (1 2 3 4) (read-string #{1 2 3 4}) = #{1 2 3 4} (read-string {1 2 3 4}) = {1 2, 3 4} If the P part of the REPL put a tick in front of lists, they would not read back correctly: (read-string '(1 2 3 4)) = (quote (1 2 3 4)) INCONSISTENT I see the problem that token ' is already taken to be short hand for quote so to be truly consistent, I might be compelled to argue that (read-string '(1 2 3 4)) should, seeing some hypothetical list start multi-char token '( just like set-start is #{ , be: = '(1 2 3 4). You'd need two single quotes: ''(1 2 3 4) to get quote '(1 2 3 4) ... Wheras (1 2 3 4) means call 1 with ... I'll have to reread the explanation about the repl phases, but maybe I'm wondering if things don't have to be quoted if lists had the syntax I describe, and requests for function invocation had a simple paren. Then you are not saying, treat this as data, do not eval. You are just saying, see my single quote paren token? That's for lists. Maybe it would be clearer if I proposed some other, lesser-used chars, like %(1 2 3 4) or even 1 2 3 4. That is, I'm not so much saying, this needs to be treated as data and not eval'd as I am simply saying, this is the 'list' data structure as opposed to some other. Now, if you ever need to read in a program and treat it like data, well, what structure would you like to put it in? A list? A vector? A string? This is, indeed, where I am fuzzy on lisps, but it seems like you parse it as desired and put it where/how you like it. Why is there an assumption
Re: repl output for list seems inconsistent and a holdover from yesteryear
I think I understand more now though, everyone. Thanks. clojure chose lists for the data structure for code so lists sort of have a special place in the language. Thanks again. On Fri, Oct 28, 2011 at 1:13 AM, e evier...@gmail.com wrote: On Thu, Oct 27, 2011 at 8:26 PM, Mark Rathwell mark.rathw...@gmail.comwrote: Maybe it would be clearer if I proposed some other, lesser-used chars, like %(1 2 3 4) or even 1 2 3 4. That is, I'm not so much saying, this needs to be treated as data and not eval'd as I am simply saying, this is the 'list' data structure as opposed to some other. A list data structure and a list code structure are the same. why wasn't vector chosen for code? The only difference is that the programmer decides when one should not be evaluated. By creating separate syntax for a list data structure you are in essence creating a different structure for lists of data than lists of code, and you no longer have a straightforwardly homoiconic language. This seems like a hugely important thing for me to grock, but it is easier to grock in languages that, say, ONLY have lists. Otherwise it seems like code is arbitrarily ONE of the data structures and, therefore is NOT homoiconic with respect to any other data structure. Why is there an assumption that code as data means code as lists? Or is there? This is the key to everything. Code is data yes, fine. but data doesn't always mean list in *my* mind. But I'm starting to get that it was chosen to be the same thing in lisps. , data is code, they are the same structure. By treating a list of data (integers for example) differently than a list of code (function and args), you create a situation where code and data are no longer the same thing. no. code and lists are no longer the same thing. I see data as a generic concept . . .a superset, not a different set. code could be data that I haven't picked a data structure for, yet. That trait is a fundamental trait of lisps, and makes things like macros much simpler. I suspected this, too. ok. You don't have to call the structure a list, you can call it something else if you prefer, but whatever it is called, it must be the same structure that defines code and defines data. But, again, there are plenty of structures that define data differently then that which was chosen for code. So why not just have a code structure. Again, it already seems broken with respect to other structures. Here's some data. It's a vector. Here's *more* data. It's a chunk of code. Ah but it was arbitrarily decided (more from history and evolution) that *that* data is a list. Broken. On Thu, Oct 27, 2011 at 6:58 PM, e evier...@gmail.com wrote: On Oct 26, 2011 7:15 PM, Stuart Halloway stuart.hallo...@gmail.com wrote: checking out the Try Clojure: if you type the following, you get output that matches what you typed in every case except for lists. Vectors: -- [1 2 3 4] [1 2 3 4] Maps: -- {:foo bar 3 4} {:foo bar 3 4} Lists: -- '(1 2 3 4) (1 2 3 4) - *INCONSISTENT* why not render this as '(1 2 3 4) ... this would make much more sense to newbies. Sets: -- #{1 2 3 4} #{1 2 3 4} This is an interesting question. Consistency is important, but consistency with what? Your mental model for what happens at the REPL needs to keep the R, E, and P steps clearly separate. Working backward: the P (Print) prints things in a way that they can be read back, where possible: (read-string [1 2 3 4]) = [1 2 3 4] (read-string (1 2 3 4)) = (1 2 3 4) (read-string #{1 2 3 4}) = #{1 2 3 4} (read-string {1 2 3 4}) = {1 2, 3 4} If the P part of the REPL put a tick in front of lists, they would not read back correctly: (read-string '(1 2 3 4)) = (quote (1 2 3 4)) INCONSISTENT I see the problem that token ' is already taken to be short hand for quote so to be truly consistent, I might be compelled to argue that (read-string '(1 2 3 4)) should, seeing some hypothetical list start multi-char token '( just like set-start is #{ , be: = '(1 2 3 4). You'd need two single quotes: ''(1 2 3 4) to get quote '(1 2 3 4) ... Wheras (1 2 3 4) means call 1 with ... I'll have to reread the explanation about the repl phases, but maybe I'm wondering if things don't have to be quoted if lists had the syntax I describe, and requests for function invocation had a simple paren. Then you are not saying, treat this as data, do not eval. You are just saying, see my single quote paren token? That's for lists. Maybe it would be clearer if I proposed some other, lesser-used chars, like %(1 2 3 4) or even 1 2 3 4. That is, I'm not so much saying, this needs to be treated as data and not eval'd as I am simply saying, this is the 'list' data structure as opposed to some other. Now, if you ever need to read in a program
repl output for list seems inconsistent and a holdover from yesteryear
long long time since I last looked a clojure, but I've never lost interest and I'm trying to find the time again. for the short version see *INCONSISTENT*, in the example at the end. I know what the answer will be here. Something like you will get used to it. or it's not important. or no one hardly uses lists anymore, anyway, since vectors are not purely contiguous. But, if you can make things better and it's easy, then why not? So here's the deal: I still think the following is only inconsistent because that's how it was in older lisps. Specifically, lists had to be quoted so the first argument wouldn't be called as a function. I asked long ago (here and in person) why, then regular functions couldn't require the quote so the paren could be reserved for the list data structure, and Rich answered that it'd simply be a pain to have to quote every function call. Well, my mind moves slowly. I'm just now realizing to ask, Ok, then how about making the list really be defined using the single quote as part of it just like sets include the sharp to distinguish them from maps?. That's a much simpler explanation than saying, you have to escape them, etc, etc. I realize this is a small matter since all I am talking about is how lists are represented as text. checking out the Try Clojure: if you type the following, you get output that matches what you typed in every case except for lists. Vectors: -- [1 2 3 4] [1 2 3 4] Maps: -- {:foo bar 3 4} {:foo bar 3 4} Lists: -- '(1 2 3 4) (1 2 3 4) - *INCONSISTENT* why not render this as '(1 2 3 4) ... this would make much more sense to newbies. Sets: -- #{1 2 3 4} #{1 2 3 4} -- 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: repl output for list seems inconsistent and a holdover from yesteryear
not necessarily. [1 2 3] is a vector that is not evaluated. Since there is no overload with things that are, there's no need for a special mark. '(1 2 3) is currently a way of say, don't evaluate this list, but it could have been: '(1 2 3) is a list that is not evaluated. No loss of generality. it's a special type of list. One that's not evaluated. as opposed to a special indicator to the repl. On Wed, Oct 26, 2011 at 6:09 PM, Mark Rathwell mark.rathw...@gmail.comwrote: The point to think about here is that functions are also lists, the same as your list of integers. The difference is that one is evaluated, the other is not. That is what the quote is saying: don't evaluate me. The quote is not actually a part of the list. It's just the way you tell the reader not to evaluate the list that follows. So the question is should all unevaluated forms be preceded with a quote in the repl output? To me that would be more confusing. On Wed, Oct 26, 2011 at 5:34 PM, e evier...@gmail.com wrote: long long time since I last looked a clojure, but I've never lost interest and I'm trying to find the time again. for the short version see *INCONSISTENT*, in the example at the end. I know what the answer will be here. Something like you will get used to it. or it's not important. or no one hardly uses lists anymore, anyway, since vectors are not purely contiguous. But, if you can make things better and it's easy, then why not? So here's the deal: I still think the following is only inconsistent because that's how it was in older lisps. Specifically, lists had to be quoted so the first argument wouldn't be called as a function. I asked long ago (here and in person) why, then regular functions couldn't require the quote so the paren could be reserved for the list data structure, and Rich answered that it'd simply be a pain to have to quote every function call. Well, my mind moves slowly. I'm just now realizing to ask, Ok, then how about making the list really be defined using the single quote as part of it just like sets include the sharp to distinguish them from maps?. That's a much simpler explanation than saying, you have to escape them, etc, etc. I realize this is a small matter since all I am talking about is how lists are represented as text. checking out the Try Clojure: if you type the following, you get output that matches what you typed in every case except for lists. Vectors: -- [1 2 3 4] [1 2 3 4] Maps: -- {:foo bar 3 4} {:foo bar 3 4} Lists: -- '(1 2 3 4) (1 2 3 4) - *INCONSISTENT* why not render this as '(1 2 3 4) ... this would make much more sense to newbies. Sets: -- #{1 2 3 4} #{1 2 3 4} -- 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: How to read project.clj file.
On 08/09/2011 05:35 AM, Shantanu Kumar wrote: On Aug 9, 12:22 pm, mmwaikar mmwai...@gmail.com wrote: Hi, Assuming there are some DB credentials specified in a project.clj file as a map, how should I read those credentials in my clojure code - 1) should I use slurp and then parse that text? 2) should I (use 'leiningen.core) and then (load-file project.clj) 3) or something else Please let me know the best / idiomatic way to accomplish this. project.clj is available to Leiningen plugins. Assuming you are open to put the DB credentials elsewhere, I'd suggest putting it in another file that can be easily discoverable. This idea is implemented in Clj- DBCP: https://bitbucket.org/kumarshantanu/clj-dbcp/overview (jump to the section Create DataSource from `.properties` file) Regards, Shantanu When it comes to loading config options, I always use my Ciste library which has the ciste.config namespace. By default, it looks for a file named config.clj in the root of the project. config.clj contains a map with the keys being the environment names and the values are maps of config options. It needs a bit more work, but it serves my purposes. The config function will either return the config map, or it will look up the passed params in the map. (use 'ciste.config) (environment) = :development (load-config) (config :database :username) = root Even if you don't use Ciste (there's a lot of stuff in there that may not be relevant to your project) The config ns should at least get you started. https://github.com/duck1123/ciste/blob/master/src/main/clojure/ciste/config.clj https://github.com/duck1123/ciste signature.asc Description: OpenPGP digital signature
Re: Efficient queue types for Clojure.
interesting. maybe I can change my interface in this thing I abandoned a while back: http://code.google.com/p/jc-pheap/ to match that of the contrib, priority map. I had gotten stuck figuring out the right interface/usage/idioms for clojure and kinda messed the whole thing up in later checkins. Then clojure went to GIT and I pretty much lost the remaining interesting having started in svn. but now I have a reason again... if I can ever get a comfortable programming environment in clojure (never was able to before). I can see how it works compared to work others are doing. thanks. On Sat, Jan 22, 2011 at 2:14 PM, Mark Engelberg mark.engelb...@gmail.comwrote: Clojure already has a built in queue. The empty queue is: clojure.lang.PersistentQueue/EMPTY and then you can use all the usual conj/into/pop/peek functions on it. For some reason, PersistentQueue is not documented, so new users have no reason to know about it until they happen to ask about it here. You might be interested to compare your priority queue implementation to my priority map in 1.3 alpha's contrib, which also supports updating items' priorities. As far as I can tell, your priority queue's pop is not O(1), because the underlying sorted map doesn't support first in O(1). It's actually O(log32#of priorities). My priority map is similar, and I agree that this behavior is quite fast, but it's worth noting that it's not truly O(1). -- 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: Idiomatic way to document defn's
Paul deGrandis paul.degran...@gmail.com writes: (defn create-session! Create shared sessions and their associated channel. Arguments: I've found the two-space indentation to be a brittle convention that's not going to port well to other presentations of the text, or adapt well to a change in the `doc' function (and `print-doc'). It's weird that a continuation line starting at column zero doesn't print as being left-aligned with the first line. -- Steven E. Harris -- 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: Chunking is making my life more difficult.
ehanneken ehanne...@pobox.com writes: I spent a long time debugging some Clojure code yesterday. The essence of it looked similar to this: (defn items [] (mapcat expensive-function (range 0 4000 100))) . . . (take 5 (items)) . . . I tried to distill the problem down by defining a non-chunking range function (a simple variant), then working outward from there to see what else is evaluating a surprising number of times. , | (defn non-chunked-range | [start end] | (prn (format In non-chunked-range with %d and %d. start end)) | (lazy-seq |(when-not (= start end) | (cons start (non-chunked-range (inc start) end) ` Note that `mapcat` is defined in terms of `map` and `concat`. First let's confirm that `map` is not eager: , | ;; Draws one, and evaluates lazy sequence function twice: | (take 1 | (map #(list %) |(non-chunked-range 0 10))) ` Experimenting with the argument to `take` shows that the lazy sequence function is evaluated as expected: a number of times equal to the argument plus one for the terminal case (n + 1). Now add `concat` into the mix to make sure it's not eager: , | ;; Draws two, and evaluates lazy sequence function three times: | (concat (take 2 (non-chunked-range 0 10))) ` That works as expected. Now add `apply` to `concat` as `mapcat` does to flatten the input lists: , | ;; Draws one, and evaluates lazy sequence five times: | (take 1 | (apply concat | (map #(list %) | (non-chunked-range 0 10 ` Whoah! Where did the extra three evaluations of the lazy sequence function come from? Note that this one calls on the function /five/ times. Here is the mapping of the argument to `take` and the number of times the function is called: take calls = 0 5 1 5 2 5 3 5 4 6 5 7 ... n n + 2 I read the source for `concat`, but I don't see what it's doing to force the extra evaluations both below four arguments and the extra one (yielding n + 2) with four or more arguments. What's responsible for this difference in behavior? -- Steven E. Harris -- 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: Regarding The Implementation of 'merge-with'
Daniel Werner daniel.d.wer...@googlemail.com writes: (some identity maps), on the other hand, checks whether there is any non-empty map *in the coll of maps*. By non-empty here, do you really mean non-nil? I don't see how the identity function would tell you whether any of the maps are empty or not. -- Steven E. Harris -- 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: Idiomatic Way to Keep a Variable Private to a Namespace
ataggart alex.tagg...@gmail.com writes: It's fairly common to let over a function, e.g.: So common, in fact, that Doug Hoyte wrote a book about it: Let Over Lambda http://www.letoverlambda.com/ -- Steven E. Harris -- 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: precise numbers
cej38 junkerme...@gmail.com writes: (defn float= ([x y] (float= x y 0.1)) ([x y epsilon] (let [scale (if (or (zero? x) (zero? y)) 1 (Math/abs x))] (= (Math/abs (- x y)) (* scale epsilon ) You're scaling epsilon incorrectly here. Epsilon defines the smallest value that yields a value greater than one when added to one. If you're not using it along with one, you're using it incorrectly. What you need to do is scale epsilon by having its exponent match the value with which you want to use it, while maintaining its mantissa. The C library offers functions ldexp()¹ and frexp()² to split and scale the exponent of a floating point number, respectively; Common Lisp offers DECODE-FLOAT³ and SCALE-FLOAT for the same purpose. I don't know of any standard functions in Java -- or Clojure -- that allow one to destructure a floating point number like this. It's possible to use Float#floatToRawIntBits(), an understanding of IEEE 754, and tweezers to get there. If you assume you have a function called `scaled-epsilon' that accepts the exemplar value with which you intend to use epsilon, (defn scaled-epsilon [n] ...) you can use the following function `same?' to compare your floating point values, assuming they're nonnegative: , | (defn same? | [m n] | (if ( n m) | (sufficiently-close? n m) | (sufficiently-close? m n))) | | (defn- sufficiently-close? | [smaller larger] | (or (zero? larger) | (if (zero? smaller) | ( larger (scaled-epsilon 0.0))) | (zero? (- 1 (/ smaller larger) ` Note too that scaling epsilon must take into account whether you intend to add it or subtract it from some companion number. It's common to use the word epsilon to mean some fudge factor without considering what the value really means for a floating point number. Indeed, using it properly in Java is still too difficult. Footnotes: ¹ http://www.dinkumware.com/manuals/?manual=compleatpage=math.html#frexp ² http://www.dinkumware.com/manuals/?manual=compleatpage=math.html#ldexp ³ http://www.lispworks.com/documentation/HyperSpec/Body/f_dec_fl.htm#decode-float http://www.lispworks.com/documentation/HyperSpec/Body/f_dec_fl.htm#scale-float -- Steven E. Harris -- 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: Idiomatic Way to Build String or Simply Use StringBuilder
Mark Engelberg mark.engelb...@gmail.com writes: str uses a string builder behind the scenes, so it's efficient this way. If the `str' implementation didn't take the input sequence to be lazy, it could figure out how long the resulting string needed to be, and construct the StringBuilder using the single-integer constructor, ensuring that no reallocation and copying occurs. Some temporary allocation would still be necessary to hold the Object-to-String projection, as `str' calls Object#toString() on each argument, rather than assuming the arguments are already of type String. -- Steven E. Harris -- 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: Literal collection of numbers - prefer list or vector?
ataggart alex.tagg...@gmail.com writes: Vectors also permit evaluation of the literal collection's elements: user= [(+ 1 2) (+ 3 4)] [3 7] user= '((+ 1 2) (+ 3 4)) ((+ 1 2) (+ 3 4)) That's a false distinction. You used `quote' rather than `list'. Macroexpand your form to see: , | user (quote ((+ 1 2) (+ 3 4))) | ((+ 1 2) (+ 3 4)) ` Quote is not a list constructor. It simply returns what the reader had constructed without evaluating it, and in this case, the reader had constructed a list. What you should have supplanted the vector literal reader with was the `list' function: , | user (list (+ 1 2) (+ 3 4)) | (3 7) | user (vector (+ 1 2) (+ 3 4)) | [3 7] ` -- Steven E. Harris -- 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: Literal collection of numbers - prefer list or vector?
David Sletten da...@bosatsu.net writes: Umm, kind of...The single quote is a macro character not a real macro. And I didn't say it was a macro. It's a macro character tied to a reader macro, and it participates in read-time macroexpansion. , | user (quote (a 'b)) | (a (quote b)) ` [...] The reader silently converts 'pung to (quote pung) prior to evaluation, so you have to come at it in a roundabout way: That's not conspiring; that's read-time macroexpansion working as intended. -- Steven E. Harris -- 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: Why so?
David Nolen dnolen.li...@gmail.com writes: Clojure functions categorized: http://clojuredocs.org/quickref/Clojure%20Core Wow, that is very nice -- especially the expandable view of the implementation source. -- Steven E. Harris -- 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: What is the reason Lisp code is not written with closing parenthesis on new lines?
On 8/18/10 1:32 PM, Brian Goslinga wrote: Putting them on separate lines put the focus on the wrong element of the code. You do not want to be focusing on the parentheses, you want to be focusing on the structure of the code. The idiomatic lisp formatting style uses indentation to reveal the large scale structure of the code, and so the parentheses can be neatly tucked away. With a little experience, the parentheses will start to fade from view. Additionally, putting them on separate lines waste vertical space, and you should be using an editor that supports paren matching so you don't need to count them. Generally, when I am working on a function, I will put the closing parens anywhere with a ton of whitespace all around. Once I'm done with the function, I make sure to delete all of the excess breaks so that it's a nice neat block of code. Using paredit in emacs makes it really easy to handle the closing parens. I'm sure there are other good tools for the other editors. signature.asc Description: OpenPGP digital signature
Re: Protocols and default method implementations
Matthew Phillips mattp...@gmail.com writes: ;; A node has a data attachment and (possibly) children (defprotocol Node (data [n]) (children [n])) (deftype SimpleNode [d] Node (data [n] d) (children [n] [])) ;; In version 2, I add want to add pretty-printing (defprotocol PrettyPrintableNode (pretty-print [n])) ;; Make anything potentially pretty-print'able (extend-type Object PrettyPrintableNode (pretty-print [n] (str A node: (data n I'm confused by the mixture of formality and looseness here. When you extend this way, binding this `pretty-print' implementation to arguments of type Object, you're implicitly requiring that argument n satisfies the protocol Node -- because you call the `data' function on it. But if the function `data' would work on any kind of Object, then so too would any call to `pretty-print', right? Should the call to `data' within the `pretty-print' definition above require some mention of protocol Node? In other words, what's the difference between using `extend-type' here on Object and just writing , | (defn pretty-print | [n] | (str A node: (data n))) ` My experiments in the REPL don't show any difference in behavior. Being able to define a normal `pretty-print' function above differs from the generic function system in Common Lisp. There, if one has defined a generic function with `defgeneric', and one later tries to define a normal function with the same name, the normal function replaces the generic function, and the compiler may emit a warning. Working the other way, though, one may not define a generic function -- using `defgeneric' or `defmethod' -- if the function name is already bound to a normal function, macro, or special operator. Is there supposed to be a difference between the normal function `pretty-print' I wrote above and the function defined in the `extend-type' form quoted above? -- Steven E. Harris -- 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: Idea for personal Clojure project
On 7/28/10 5:34 PM, Mark Engelberg wrote: Wordnet is the main existing thing that comes to mind as related to your idea. You might also want to look into Freebase. Here's a Clojure client you can use to query their data. http://github.com/rnewman/clj-mql signature.asc Description: OpenPGP digital signature
Re: persistent LRU cache (request for input)
Peter Schuller peter.schul...@infidyne.com writes: I can turn 'get' into 'peek' and have another function that more specifically advertises, by its name, that it produces both a value and a new cache. That only helps naming though, and not usability of said function. Yes, and though it does so for a completely different reason, there's precedence for this in the Standard C++ Library's stack¹, queue², and vector³ class templates (as well as some other containers). There, reading (e.g. std::queue::front()) and mutating (e.g. std::queue::pop()) are kept separate, because mutating exposes us to exception safety concerns; for popping an item off the front of a queue, trying to return a value that needs to be copy-constructed could trigger an error /after/ the underlying container has been mutated to no longer contain that value. What's less clear to me here, though, is how a caller would know when to call on the mutating LRU adjuster function. If the peek function tells him what he needed to know, you're still left with the odd contract of needing him to call some other function to actually note his interest's effect on the LRU ordering. Footnotes: ¹ http://www.dinkumware.com/manuals/default.aspx?manual=compleatpage=stack.html#stack ² http://www.dinkumware.com/manuals/default.aspx?manual=compleatpage=queue.html#queue ³ http://www.dinkumware.com/manuals/default.aspx?manual=compleatpage=vector.html#vector -- Steven E. Harris -- 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: persistent LRU cache (request for input)
Peter Schuller peter.schul...@infidyne.com writes: lru-peak - [value] I take it you meant peek, not peak. [...] One possibility I was thinking of was that, since the expected use case of an LRU cache is so specific, it may be acceptable to have the lru library itself provide a side-effect aware interface directly. The LRU aspect of the cache is no business of those using the get and put parts of the interface. Those callers should just think they're using an associative array, dictionary, map, or whatever you want to call it. That having called get may influence what gets evicted next from some other function isn't germane to the caller's interest. Unless you're willing to use something like the State monad to represent (and help hide) the side effects of calling your get function, I think you're better of making no claim about what get does beyond its normal contract: promise only that it returns the value mapped to the given key, if any. This data structure doesn't seem like a good fit for a functional-style interface. -- Steven E. Harris -- 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: auto-indent in Counterclockwise
Laurent PETIT laurent.pe...@gmail.com writes: When you say that it's hard ... '[' and ']' ..., you're talking about the original paredit.el in emacs? Actually, I was talking both about the current Emacs Lisp editing library (where `move-past-close-and-reindent' is defined) and the most recent paredit.el library available for download. Or you saw a deficiency in counterclockwise ? No, I wasn't complaining about Counterclockwise. Rather, I was noting that the /complete/ behavior of `move-past-close-and-reindent' is hard to mimic. -- Steven E. Harris -- 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: auto-indent in Counterclockwise
Laurent PETIT laurent.pe...@gmail.com writes: But to make it really clear: move-past-close-and-reindent is exactly what counterclockwise's is doing in Strict edition mode (not totally true concerning the reindentation, currently in ccw it is only reorganizing closing brackets by removing extra spaces, not reindenting lines). I see. That's good to hear. It's hard to know when you've really met the Emacs capability there. That function does so many things right that I can't bear editing Lisp code without it. That it's hard to adapt it to work with symmetric brackets (for Clojure's '[' and ']') is disappointing, and I have found the paredit package to be not much better on that front (having difficulty with balancing '{' and '}'). It has its own set of oddities. -- Steven E. Harris -- 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: auto-indent in Counterclockwise
Laurent PETIT laurent.pe...@gmail.com writes: I think it's a good feature, *if* typing the closing bracket/paren just resulted in cursoring over the one that'd already been inserted. ? See the Emacs function `move-past-close-and-reindent'. It works as the obvious counterpart to the function `insert-paretheses'.¹ Footnotes: ¹ http://www.cliki.net/Editing%20Lisp%20Code%20with%20Emacs -- Steven E. Harris -- 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: Enhanced Primitive Support
David Nolen dnolen.li...@gmail.com writes: Using loop/recur is already the beginning of code smell for anything that is not performance sensitive. [...] In your arity-overloaded example, is there any runtime cost to figure out which of the two overloads to choose each time `recur' evaluates? -- Steven E. Harris -- 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: Mac Emacs users: which version do you prefer (Aquamacs, Carbon Emacs, other?)
Moritz Ulrich ulrich.mor...@googlemail.com writes: Aquamacs integrates nice, but it changes many emacs keybinding per-default and makes it hard to change them, which is a no-go for me. Here's what I use (so far) to beat it back into shape: (cua-mode 0) (transient-mark-mode 1) (pending-delete-mode 1) ;; I'm not ready to accept the separation of the Emacs kill ring and ;; the system clipboard. (osx-key-mode 0) ;; Revert the binding for `recentf-open-files' defined in ;; /Applications/Aquamacs.app/Contents/Resources/lisp/aquamacs/macosx/aquamacs-menu.el: (global-set-key \C-x\ \C-r 'find-file-read-only) -- Steven E. Harris -- 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: review the clojure.string code
Why do some of the functions use StringBuilder (no internal synchronization) and some use StringBuffer (provides internal synchronization). Using the latter is probably a mistake. The first function -- reverse -- uses StringBuilder#reverse() to reverse the character sequence in place, and then calls StringBuilder#toString() to yield a String. Why is the final step necessary? Since StringBuilder implements CharSequence, isn't it sufficient to just return the StringBuilder? That's what the function signature promises. Calling toString() makes yet another copy of the data, so it's best avoided. Some of these functions construct instances of class StringBuilder using its default constructor, which gives it a default capacity. But most of the functions also know at the outset some reasonable size for the buffer. For instance, function `replace-first-by' could reasonably use the length of its argument s as the size of the buffer, even though the replacement for some matched substring may increase the overall length. Why does function `replace-first' unconditional call CharSequence#toString() on its argument s, when in several cases just using s as a CharSequence would be fine. Again, calling CharSequence#toString() might make a copy of the data, depending on whether the CharSequence was actually a String or something like a StringBuilder. The implementation of a function like `trim' could be more efficient, given that it's allowed to return a CharSequence. You can construct a StringBuilder of length equal to the source CharSequence, then walk the source sequence from the beginning, skipping over all whitespace, copying the non-whitespace characters, repeating until you hit the end of the source string. The right trim behavior is a little tricky, as you have to suspend the copying upon encountering whitespace, but but back up and copy that whitespace upon encountering something else before the end of the source string. Alternately, just walk backward from the end of the source string. The bonus is that you only copy the data once. With the current implementation, calling CharSequence#toString() might copy the data once, and calling String#trim() will copy it again. Rounding out the review, function `trim-newline' doesn't have to call toString() on the CharSequence yielded by CharSequence#subSequence(), as it already promises to return a CharSequence. Most Java code poisons its string manipulation efficiency by always promising to return String rather than CharSequence. You've done better in your signatures here, so I'm just encouraging you to avoid String and the extra copies it forces. -- Steven E. Harris -- 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 Concurrency Screencast Available
interesting so far. the format I first tried didn't work on my droid, but no big deal. one, kind-of Eureka moment I just had, which is somewhat blasphemous, I guess: Craig is going through how a vector is [1 2 3] but a list has to be '(1 2 3)? Well, that may be one of the turn-offs people have from other languages. Can you imagine how disruptive it would be at this point to do it the other way around? If you were starting out today without any Lisp baggage, it seems TOTALLY obvious to me that lists would have been (1 2 3), and the *calling of a function* would have been the different thing ... now that these other data structures represent themselves symbolically (vectors, sets, maps). The quote symbol (or other) should have been to call the function. That would make much more sense, but I doubt making a syntax like that would earn one many friends. Oh well, I'll keep watching. Starting out very nice. On Sat, Apr 10, 2010 at 3:06 PM, Craig Andera craig.and...@gmail.comwrote: Mobile downloads are available now. Sorry about the delay. The refs module is also up, so that's five of six. Part six by mid next week. On Sat, Apr 10, 2010 at 9:26 AM, Craig Andera craig.and...@gmail.comwrote: Right, good point: I should have seen that coming given the target audience. :) Within a few hours, a mobile download link will appear with wmvs and mp4s in a variety of resolutions so you can watch these offline on the device of your choosing. The conversion lags the rest of the process a little bit, but I'm told the upload is in progress now. Hope that helps. On Fri, Apr 9, 2010 at 7:22 PM, Jeff Heon jfh...@gmail.com wrote: I must say I appreciate video sharing sites like blip.tv and Vimeo that allows one to download and watch their videos offline. Very practical for those commuting and using portable devices 8) -- 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.comclojure%2bunsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en To unsubscribe, reply using remove me as the subject. -- 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.comclojure%2bunsubscr...@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 Concurrency Screencast Available
And ... in another Ah-ha based on an email I just received on this subject ... what should really be said here is that there should be an explicit symbol to say that the first argument of the list is receiving special treatment (the words of the emailer). Well, that got me thinking: Now I know what the symbol should really be! It should be the number zero (or one if you prefer one-based things). so (+ 1 2) is just three symbols, but 0(+ 1 2) means the first argument is the function. That makes 1(1 + 2) easy. Oh and while we are at it, then things like all the funky, confusing arrows are easy, too. You could have t(...) for thread and tf(...) for thread first (if that's different from thread) ... tl(...) for thread last. and you could have n(...) for postfix. wow. this seems powerful to me, and more obvious. Another choice would have been to use something else for lists, like 1 2 3, but I guess that would have looked a little too much like templates or html (more blasphemy). On Sat, May 1, 2010 at 11:30 AM, e evier...@gmail.com wrote: interesting so far. the format I first tried didn't work on my droid, but no big deal. one, kind-of Eureka moment I just had, which is somewhat blasphemous, I guess: Craig is going through how a vector is [1 2 3] but a list has to be '(1 2 3)? Well, that may be one of the turn-offs people have from other languages. Can you imagine how disruptive it would be at this point to do it the other way around? If you were starting out today without any Lisp baggage, it seems TOTALLY obvious to me that lists would have been (1 2 3), and the *calling of a function* would have been the different thing ... now that these other data structures represent themselves symbolically (vectors, sets, maps). The quote symbol (or other) should have been to call the function. That would make much more sense, but I doubt making a syntax like that would earn one many friends. Oh well, I'll keep watching. Starting out very nice. On Sat, Apr 10, 2010 at 3:06 PM, Craig Andera craig.and...@gmail.comwrote: Mobile downloads are available now. Sorry about the delay. The refs module is also up, so that's five of six. Part six by mid next week. On Sat, Apr 10, 2010 at 9:26 AM, Craig Andera craig.and...@gmail.comwrote: Right, good point: I should have seen that coming given the target audience. :) Within a few hours, a mobile download link will appear with wmvs and mp4s in a variety of resolutions so you can watch these offline on the device of your choosing. The conversion lags the rest of the process a little bit, but I'm told the upload is in progress now. Hope that helps. On Fri, Apr 9, 2010 at 7:22 PM, Jeff Heon jfh...@gmail.com wrote: I must say I appreciate video sharing sites like blip.tv and Vimeo that allows one to download and watch their videos offline. Very practical for those commuting and using portable devices 8) -- 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.comclojure%2bunsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en To unsubscribe, reply using remove me as the subject. -- 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.comclojure%2bunsubscr...@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 Concurrency Screencast Available
doesn't sound like you are misunderstanding. Data is data, first and foremost in that model. you have to work to turn something into a function. other than functions, everything is data. That's the JSON way, for sure. When something is a function, you see things like eval and function in javascript, at least. But they only have two types, arrays and objects (dictionaries). On Sat, May 1, 2010 at 11:06 PM, Alex Osborne a...@meshy.org wrote: e evier...@gmail.com writes: Can you imagine how disruptive it would be at this point to do it the other way around? If you were starting out today without any Lisp baggage, it seems TOTALLY obvious to me that lists would have been (1 2 3), and the *calling of a function* would have been the different thing ... now that these other data structures represent themselves symbolically (vectors, sets, maps). Interesting, although in the case of idiomatic Clojure it's actually very rare to want to use a list literal. Most of the places you'd use a list literal in other lisps, a vector probably makes more sense in Clojure. I'm also not sure the code-is-data thing works so well when you reverse quotation like that as it means you'd have quotes on every nested level instead of just the outside, which would make macros more difficult to write (at least without any other changes), but I may be misunderstanding your idea. -- 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.comclojure%2bunsubscr...@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 1.2 seq fn enhancement FAQ
Phil Hagelberg p...@hagelb.org writes: Actually I do consider sets to have keys, since internally they are implemented using maps, so the exact same semantics apply for their lookup. They're just maps where the key and value are the same thing: But that implementation is one of convenience, of possibly admirable laziness, and it's none of our business. A key is something apart from a value it refers, but in sets, there's no separate value being referred to. The value is the only thing in play. Where we get hung up in software is with the flexibility to define equality or sufficient sameness in set implementations by taking only part of the stored values into account. The same idea doesn't exist in the mathematical view of sets. Our software would be much clearer if sets didn't tolerate these key comparison views, and would instead force one to use a map in cases where such a key comparison view (being something less than the value itself) is necessary. -- Steven E. Harris -- 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: Why I have chosen not to employ clojure
I'm starring that post. Still haven't gotten Aquamacs working with clojure. will try yet again tonight. On Tue, Mar 23, 2010 at 3:28 PM, Carson c.sci.b...@gmail.com wrote: I second Lee's thought -- my work as a grad student is AI research, not application development. I'm glad I discovered Incanter's package (three lines of instructions [1]) that allows me to run a Swank server that I can easily connect to from Emacs (and Slime from the Emacs end can be easily installed thru Elpa). The part about getting Swank/ Slime easily going achieves the threshold on the editor front. [1] from http://data-sorcery.org/2009/12/20/getting-started/ $ git clone git://github.com/liebke/incanter.git $ cd incanter $ mvn install then $ bin/clj to get a repl on the terminal or $ bin/swank to start up a swank server. For me, if it takes more than three lines on the terminal, it's just too much. :) So labrepl sounds interesting from what I read here (especially as it includes Incanter?). It'd be great if it also has Swank as part of it so Emacs can connect to it (or does it already?). Thanks! Carson On Mar 23, 11:53 am, Lee Spector lspec...@hampshire.edu wrote: I like where this is going but I would suggest that there's a significant audience (including me and most of my students) in what we might call category A.01: Want to explore and even do some real work, but not necessarily work involving deploying apps, connecting to databases, working with third party code, or anything else that requires a full-featured production environment or project management system. A working REPL with access to contrib and a classpath that allows load to work (all of which I can get pretty painlessly with ClojureX) is *almost* enough, but the 0.01 extra that makes an enormous difference is an editor with the minimal functionality of clojure-aware indentation and bracket matching. I'm intrigued by what I've read here about labrepl, but can someone tell me if it's possible that the lein installation step will mess up my existing setup in any way? Not knowing anything about lein, and having had a confusing time creating my setup that now works (with ClojureX + slime), I don't want to endanger it. This is part of the reason that I (and I presume others who have expressed similar sentiments) really like the idea of a getting started package for which the installation process is literally just download and double click or maybe download, unzip, and double click. (And if you don't like it, throw away what you downloaded and the rest of your system will be unchanged.) For me the functionality threshold for such a package, which would not only get me started but allow me to do serious work (AI research, not application development) and teach using Clojure, is: a REPL, access to contrib, a classpath that lets load find my source files, and a clojure-indenting, bracket-matching editor. Anything else is gravy, but most of the existing getting started setups fall short of my threshold at least on the editor front. -Lee On Mar 23, 2010, at 11:30 AM, Stuart Halloway wrote: I think it is important to be clear about the difference between: (A) exploring Clojure (non trivially, including interesting Java libraries) (B) deploying Clojure into production. I nominate the labrepl (http://github.com/relevance/labrepl) as a solution for (A). It already includes interesting libraries (e.g. compojure, incanter), and it has instructions for working with different IDEs (which I hope the community will improve upon). I don't think there is, or needs to be, a one-size-fits-all solution for (B). That's what the Java ecosystem is for. Plus, beginners don't need (B). Stu So perhaps it would be worthwhile to create, like jruby, a single zip/ tgz file containing clojure, clojure-contrib, and a reasonable bin/clj file that will find at least the core clojure jar files on its own? I don't see how you're going to actually deploy any clojure apps, or connect to a database, or really use any third party code at all without understanding how java's classpath works but at least you can get a REPL going. -- 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.comclojure%2bunsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en To unsubscribe from this group, send email to clojure+ unsubscribegooglegroups.com or reply to this email with the words REMOVE ME as the subject. -- You received this message because you are subscribed to the Google Groups Clojure group. To post to this group,
Re: Why I have chosen not to employ clojure
think about the difference between putting flash or python on a machine compared to clojure. there's more of a system-level path feel to those things (even though each user can have their own environment). I mean, you can add a clj script to your path and get the same effect, but that's what's different. He's not talking about someone messing around with a language ... he's talking about trying to imagine that the language is now part of the system. Again, Fantom sort of has this feel. Part of the DEFAULT instructions is to mess with your path and get things going. Check out the Fantom website. So simple and straight forward and inviting. On Sun, Mar 21, 2010 at 11:07 PM, Seth seth.schroe...@gmail.com wrote: I hate to feed trolls, but this is a solid example of passive- aggresive behavior. Also, ignoring plausible sounding, spell-checked diatribes is bad. The installation of one or two jar files from a Maven repository is par for the JVM course. Deployment? Works on any reasonable JVM out there. Could the install/deploy behavior be improved? Sure, but try targeting something less ubiquitous than ant. Slackware more modern than Ubuntu?? Contrasting Clojure with Flash on Ubuntu really takes the cake. Flash has never had a good reputation outside of Windows. Also, either the poster is running as root (!) or has somehow forgotten a very important su/sudo between steps 2 and 3. Either way, no sysadmin has to be convinced. Wresting with pigs is bad because you get dirty and the pig likes it. On Mar 21, 2:42 pm, Tim Johnson t...@johnsons-web.com wrote: I have evaluated clojure for the last couple of days, and it is both my own professional decision and my recommendation to the professional organizations that I belong to and report to that clojure is not ready for prime time. Before any of you think that I am a disgruntled newbie turned troll, know the following: 1)As soon as I see the copy of this email in my clojure mailbox, I will unsubscribe from this mailing list, delete the clojure mailbox and I will not be following up in any way. 2)In as much as clojure is a new programming language with a small but enthusiastic user base and a brilliant developer I confess to a certain deja vu here. That would be rebol 10 years ago. Brilliantly conceived, brilliantly designed by one of the best programmers on the planet. Never went anywhere. I've used rebol for 10 years steadily and made a lot of money with it, but there is almost 0 demand for rebol programmers out there. 3)Although I may be a noob with it comes to clojure and even more of a noob when it comes to java, I have been a professional analyst and programmer for 21 years and own my own company. Many seasoned programmers, analysts and system adminstrators look at a new system as something to employ. As a front end for java, I do not consider clojure to be employable. I think that clojure is brilliantly conceived and it is clear from what I have read of Rich Hickey's words that his vision is right in the same channel with mine, but that is not the problem. The fact that I respect the developer and the product is the reason that I have taken this time to write this email. The reason I choose NOT to employ clojure can be summed up in three words. --- Install and deploy. --- I consider this to be clojure's fatal weakness. Certainly I can get clojure up and running, but selling clojure to a sysadmin is going to be a problem at this time. There was a time when PHP was NOT present on virtually all webservers. PHP got it's foot in the door because it was very easy to deploy. Consider the two threads that I started up - one is titled Web programming in Clojure - there's the good stuff. Generous reponse, lots of input. The other one is titled Installation issues on slack 13.0 (ant?). This where it all falls apart. Sadly, this is like the first impression and we all know how lasting first impressions are. In fact as you can see, the thread ended with no resolution. I'm sorry to pick on steve but his response is a case study * Steve stephen.a.lind...@gmail.com [100320 05:24]: Reading the getting started page on the website will get you further still :http://clojure.org/getting_started Sadly inadequate! Check out the comparable kawa resources and instructions for a better example. If you do need ant then a more modern distro will make your life much easier (eg. apt-get install ant). Again, so inadequate. I also use ubuntu. Have for years. apt-get is a thing of beauty. When it works. And bye the way, slackware is much more modern when it comes to up-to-date build tools. So know I not only have to sell clojure to the sysadmins, I have to sell them ubuntu too? Good luck with that! Here's how I installed the flash player on my system. 1)Downloaded
Re: Why I have chosen not to employ clojure
On Mon, Mar 22, 2010 at 1:26 AM, cej38 junkerme...@gmail.com wrote: I am a physicist by training and practice, this means that I am an expert on Fortran 95. To say my exposure to Java is minimal would be generous. And until last year when I heard about Clojure from a friend, I thought LISP was a speech impediment. Setting up Clojure was a MAJOR problem for me, what with getting path's and classpaths right. (Figuring out what a classpath is was a challenge.) If it wasn't for the very patient help of a CS friend of mine, I would not have figured it out. I think the documentation assumes that the user is comfortable with Java. I feel like I am being asked to learn Java so that I can learn Clojure. Amen! I can understand why this was the initial road to get functionality going quickly, but I hope this goes away. I am now an avid Clojure user, but there really does need to be better descriptions of how to set Clojure up on the website. On Mar 21, 4:37 pm, Quzanti quza...@googlemail.com wrote: Reading his post I got the impression he was a bit of an egocentric (a bit more information about himself than was relevant), those sorts tend to overreact. However I can imagine the whole just bung the jar file on your classpath thing wouldn't make much sense for a java newbie. It may highlight the need for some special 'getting started' documentation for Lisp programmers who have never used java, which I understand to be one target audience of clojure. I don't understand the complaints about installing Clojure. As far as I know there's nothing required to 'install' Clojure beyond downloading the clojure.jar, other than I guess having a working Java installation. -- 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.comclojure%2bunsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en To unsubscribe from this group, send email to clojure+ unsubscribegooglegroups.com or reply to this email with the words REMOVE ME as the subject. -- 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 To unsubscribe from this group, send email to clojure+unsubscribegooglegroups.com or reply to this email with the words REMOVE ME as the subject.
Re: Why I have chosen not to employ clojure
there's a positive reason to say all that stuff as if to say, and it's not that I'm a slouch. I have been able to succeed with other technology. I've personally had tons of trouble getting going with clojure, and I use java all the time. I think the ideas in clojure are awesome, and I like the language, but if folks have never looked at Fan/Fantom ... as far as getting into it, *that's* about the gentlist you can get into anything. The website was written in Fantom, it's a one stop shop for getting started ... not that I like that language better or anything, but, seriously ... that's a fun exercise. It's very inviting and welcoming and I wish that a page could be taken from that approach -- I think he wouldn't have had any of the same opinions if it had. And I realize I'm not being very concrete: I'd had plans to write up what I thought some specific differences were. Now I'm just left with an impression ... an impression that Fantom wants you to LOVE that language . . . .and an impression of clojure that you have to want to love clojure (so then you have to make a lot of complicated arguments as to why that is so, which, by the way, I think are beautifully presented in Clojure In Action). And don't get me started on trying to get emacs or vi all hooked up on my mac. I've never succeeded. Summary: I agree to some extent. clojure is awesome. I wish I could use it at work, but it's an incredibly hard thing to sell. On Sun, Mar 21, 2010 at 4:37 PM, Quzanti quza...@googlemail.com wrote: Reading his post I got the impression he was a bit of an egocentric (a bit more information about himself than was relevant), those sorts tend to overreact. However I can imagine the whole just bung the jar file on your classpath thing wouldn't make much sense for a java newbie. It may highlight the need for some special 'getting started' documentation for Lisp programmers who have never used java, which I understand to be one target audience of clojure. I don't understand the complaints about installing Clojure. As far as I know there's nothing required to 'install' Clojure beyond downloading the clojure.jar, other than I guess having a working Java installation. -- 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.comclojure%2bunsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en To unsubscribe from this group, send email to clojure+ unsubscribegooglegroups.com or reply to this email with the words REMOVE ME as the subject. -- 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 To unsubscribe from this group, send email to clojure+unsubscribegooglegroups.com or reply to this email with the words REMOVE ME as the subject.
Why do functions in the state monad only accept one value?
I've been comparing the definition of the Clojure's state monad -- state-m in clojure.contrib.monads -- to definitions I've found elsewhere, and there's a facet of the Clojure definition that's puzzling: Why do monadic functions in state-m only accept one argument (a basic value) and return a monadic value (a function accepting a state), as opposed to accepting both the basic value and a state? Looking at the definitions for the state monad in Haskell, it seems ambiguous as to whether the monadic functions accept one or two values, but then functions in Haskell can all be curried, so it's hard to tell. The paper Monads for functional programming¹ by Philip Wadler shows the following definition of the bind operator on page 9: m * k = \X.let (a, y) = m x in let (b, z) = k a y in (b, z) Note the application of function k is shown as k a y where a is the basic value resulting from m and y is the state as updated last by m. This definition suggests that function k doesn't make much sense without these two arguments supplied. Again, though, this is Haskell, so supplying multiple arguments at once doesn't mean much. In the Haskell tutorial's article The State monad², the definition looks more like Clojure's: (State x) = f = State $ \s - let (v,s') = x s in runState (f v) s' There we see monadic function f applied to basic value v, and then the result applied to the pending state s'. Clojure's definition is as follows: (fn m-bind-state [mv f] (fn [s] (let [[v ss] (mv s)] ((f v) ss There, similarly, monadic function f is applied first to basic value v, and then the result applied to the pending state ss. My question: What's the benefit of having the monadic function accept only the basic value, deferring consideration of the state, as opposed to having it accept both the basic value and the pending state together? As I write this, I realize that following Clojure's definition ensures that monadic functions return monadic values, and here a monadic value is a function that accepts a state. What's been difficult, though, is actually writing monadic functions for use in the state monad. It feels wrong to define a function whose outcome depends both on the input basic value and the input state, but to have to cut the function in half, receiving the two values as separate steps. Sometimes the function depends only upon the input value, in which case the `m-result' is sufficient to provide the resulting monadic value. Sometimes the function depends on both the input value and the state, in which case we have to just close over the input value and defer its consideration until we receive the state later. What would be lost by defining Clojure bind operator like this: (fn m-bind-state [mv f] (fn [s] (let [[v ss] (mv s)] (f v ss Is there more to it than, Monadic functions must return monadic values? Any clarifying advice would be welcome. Footnotes: ¹ http://homepages.inf.ed.ac.uk/wadler/papers/marktoberdorf/baastad.pdf ² http://www.haskell.org/all_about_monads/html/statemonad.html -- Steven E. Harris -- 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: Why do functions in the state monad only accept one value?
Jarkko Oranen chous...@gmail.com writes: [...] This way, you can write a function that works under many different monads, as long as it uses the generic facilities to return monadic values. eg. a lifted inc: (defn m-inc [v] (m-result (inc v)) which can be used in the state monad as an argument to bind, even though it doesn't care about the state at all. Ah, I hadn't realized that such functions -- of which I've now written several for use in the state monad -- actually say nothing about the state, and can be used in other monads as well. That was helpful to consider. -- Steven E. Harris -- 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: Why do functions in the state monad only accept one value?
Michał Marczyk michal.marc...@gmail.com writes: a State-using programme builds up a stateful computation first, then uses runState (or perhaps execState / evalState) to run it as a whole; only at this final step does the initial state actually get poured into the opening of the monadic pipe, as it were. That's a good metaphor. [...] You can use it multiple times, each time injecting a different initial value of state. Ah, but here's where part of my confusion arises. With this treatment of such a built-up computation, it's a kind of a zero-argument function, in that there's no way to pass in a basic value to kick it off. Where does the first basic value to be fed into the first monadic function come from? Presumably it comes from the first monadic value in the pipe. In your description above, it sounds like this first monadic value must be committed to when buld[ing] up a stateful computation first. In the parser examples I've seen, the state provides the input value. It's hard to find examples of other kinds of computations using the state monad, but even something like do these arithmetic steps to some input number, and count the number of operations in the state would want to start off with some number as input, distinct from the state, which would presumably start off with a count of zero. That sounds like we'd have to build up the arithmetic steps as a monadic function, not a monadic value, which we'd bind to (m-result initial-value) to kick it off. [...] BTW, if you feel you'd rather write something like (defn put [v s] [v v]) than a two-tier function like c.c.monads/set-state, you're free to do so; then you can use #(partial put %) for set-state. Interesting idea. PS. Sorry if this is a bit chaotic... I like the challenge of following your mental process. More examples on this topic would be welcome. -- Steven E. Harris -- 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: Writing a put-if-absent operation a la Java's ConcurrentMap
Stuart Halloway stuart.hallo...@gmail.com writes: It is mort important to focus on the semantics (commutative or last- one-wins) than the implementation details. That's a tough pill to swallow. I understand the benefits of specifying behavior to allow flexibility in an implementation, but here I think the behavior is still underspecified. Or maybe it's just hasn't been described well with enough comparative examples to allow it to sink in. It feels like some of our discussion is still operating on superstition. If you care about ordering, stick to alter. If you aren't sure, stick to alter. Got it. I find a counter to be a useful example. If the purpose of the counter is to keep a total count of something that happened, then you can use commute. This is true because even if commute runs once and increments the counter, but then runs into a conflict, the commute operation will be run again on a fresher value until it finally succeeds in committing without conflict. This is similar to a manually-written atomic increment operation using CAS in a spinning loop: for (int cur = val.get(); !val.compareAndSet(cur, cur + 1); cur = val.get()) ; Or: int cur; do { cur = val.get() } while (!val.compareAndSet(cur, cur + 1)); But if the counter is used as an id generator within the transaction, then order matters and you have to use alter. The key there is within the transaction, because if you used commute, the commuted operation could be repeated upon conflict at the end of the transaction and wind up succeeding, albeit with a different resulting value than the one observed within the transaction, right? -- Steven E. Harris -- 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: Using deftype to define mutually recursive data inside agent
ataggart alex.tagg...@gmail.com writes: You can use *agent* from inside an agent thread to obtain the current agent. Is this documented? -- Steven E. Harris -- 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: Writing a put-if-absent operation a la Java's ConcurrentMap
Meikel Brandmeyer m...@kotka.de writes: So using alter is the absolutely correct and nothing bad will happen. However you might construct superfluous default nodes in case the action is retried. They are not assoc'd to the map, though. Understood. Thanks for the explanation. The anonymous function is not necessary. I missed this note in the documentation, despite having run my eyes over it several times: , | Sets the in-transaction-value of ref to: | | (apply fun in-transaction-value-of-ref args) ` What leads you to the idea it would be different? Only the lack of confirming documentation walking through the behavior under conflict. I think this is the whole point about STM, that you don't have to worry about such things. Yes, but then writing with concurrency in mind is all about imagining the odd things that will almost never happen, but you need to design in anticipation of. The STM presents some magic that's supposed to alleviate the programmer of some worry, but without being clear about the scope of that magic and the problems it alleviates, I don't know which problems to ignore. There is (get the-map id (default-node)), but this does not assoc the value to the map. I assume your (default-node) is a little more complicated - and in particular non-constant. Yes, you assume correctly. I thought through whether I could work with the get-with-default operation, but concluded that I need the semantics of the Java functions I had written as examples. I think the let above solves this problem, no? Yes, I think it does. I'll either return a value that some prior thread inserted in the map or the value that I just inserted. I take it that `dosync' doesn't return any value until all of its changes can be committed without conflict, such that the returned value with follow from a successful commit against what was a consistent view of the refs involved. In contrast to alter, commute would in case of conflict just go on and assoc the id again. When you say assoc the id again, do you mean that in the example time line above, B's alteration of the map would succeed, even though A's alteration had succeeded just prior, without B retrying? If so, there's more to be explained about `commute'. I'm imagining the commit-time rules saying that if competing changes to the refs touched by `commute' can be ignored, because the changes can be applied in either order. But if the operation was something like `inc', two competing threads would both commit a value one greater than when both transactions started, which would result in a final value only one greater, rather than two, as intended. Reading the documentation again, I think these characterizations are wrong. It sounds like `commute' runs /again/ at the commit point of the transaction, but the whole transaction doesn't have to run again. It's not clear whether `commute' /always/ invokes the provided function twice, or only in the case of having detected a conflict against the target ref at the would-be commit point. I think alter is exactly the right tool. Good. I can understand `alter'. I'd still like to understand more about `commute'. I appreciate the discussion. -- Steven E. Harris -- 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
Writing a put-if-absent operation a la Java's ConcurrentMap
My application involves a graph with a node set, represented as map from integral node ID to a node structure. Several threads need to look up these node structures. This graph is constructed lazily, by which I mean that the structures representing the nodes are only instantiated upon first visiting of a given node. The per-node structures are like a color map used to guide depth-first-traversal. If I were building this map in Java, I could write an operation like this using ConcurrentMap¹: Node ensureNodeExists(Id id, ConcurrentMapId, Node map) { final Node defaultNode = createDefault(); final Node prev = map.putIfAbsent(id, defaultNode); return null == prev ? defaultNode : prev; } If there was no previous entry for the given ID, insert a default node structure and return it. Otherwise, return the current node. Given that nodes will never be deleted from the map, we could optimize this function a little: Node ensureNodeExists(Id id, ConcurrentMapId, Node map) { final Node current = map.get(id); if (null != current) return current; final Node defaultNode = createDefault(); final Node prev = map.putIfAbsent(id, defaultNode); return null == prev ? defaultNode : prev; } That involves an extra lookup in the case that the entry isn't currently in the map, but saves construction of the default node for cases where the entry is already in the map. Suppose we want to write an analogous operation in Clojure. I think the solution involves `dosync' and either `alter' or `commute', but I'm having trouble reasoning about the semantics of those operations in the face of collisions among competing threads. My first attempt: (dosync (or (*id-node-map* id) (alter *id-node-map* #(assoc % id (create-default) Ignoring the defect that each branch of the `or' form returns a different kind of value (in one case, the mapped value, in the other case, the map itself), I wondered whether it's possible that in between when I first lookup the value and find it missing and when `alter' runs that another thread could have jammed a value in there. Feeling paranoid, next I wrote this: (dosync (or (*id-node-map* id) (alter *id-node-map* #(update-in % [id] (fn [cur] (if (nil? cur) (create-default) cur)) In that case, if the value is already in the map, it looks like we still wind up changing the *id-node-map* ref even if the map didn't need to change. Several questions arise: o What happens if two threads run this operation concurrently? Will one fail and retry, backing off for finding the value now present in the map? o Is there some map updating operation better suited to my goal here? The lookup ahead of time seems like it might not be necessary. o Is there some way to capture the new value associated with the key without looking it up again /outside/ and /after/ the `dosync' form? The contract is that there's either no value associated with the key or there is a value, and once there's a value it will not change to be a different value. (These values are themselves agents.) But it's hard to tell from within `dosync' whether a proposed update to the map will be the one than wins. o Assuming that `alter' is germane to the solution, how would `commute' behave differently? I understand that `commute' doesn't block writers and hence can retry. In my case, retrying after losing in the collision should result in finding that the competing thread already bound a value to the given key in the map. It's been very difficult to find a thorough discussion of how `dosync', `alter', and `commute' behave. In particular, if a transaction touches several values with several `alter' or `commute' calls, and any one of those values wind up conflicting with a competing transaction, does the whole transaction fail and restart? Again, how do `alter' and `commute' differ in such a case? Footnotes: ¹ http://java.sun.com/javase/7/docs/api/java/util/concurrent/ConcurrentMap.html -- Steven E. Harris -- 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: Question about how to write efficient code in functional style
Someone will have an elegant solution, but what comes to my mind is a (somewhat) brute force loop-recur ... not not that much different from what you suggested. It would pass the under construction return lists to itself and a dwindling amount (rest) of the original list. Add first from the dwindling source list to the appropriate return list on each pass. When the source/input list is empty, return the constructed lists. Only one pass through the input list. The loop-recur pattern looks like it makes recursive function calls, but it's just iteration. On Sat, Feb 27, 2010 at 8:54 PM, logan duskli...@gmail.com wrote: Let's say I want to write a function that takes as an argument a list of n numbers, and returns 4 lists, a list of odd numbers that are multiples of 5, a list of even numbers that are multiples of 5, a list of odd numbers that are not multiples of 5, and a list of even numbers that are not multiples of 5. If I were writing this function procedurally, I could create 4 empty lists, and iterate through my input list once, using a compound if statement to add to the appropriate list. In functional style, I could use filter, but I can't seem to think of a solution that doesn't end up iterating through the whole list multiple times. Can someone please teach me what is the correct clojure approach? Thanks. -- 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.comclojure%2bunsubscr...@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: difference between if/when
Richard Newman holyg...@gmail.com writes: There are more subtle clues that you'll pick up in certain people's styles, too -- I'm sure my use of when has a very different pattern to a Java guy's, colored by my Common Lisp experience. I'm still undecided whether to shake this habit: , | (defmacro unless [pred body] | `(when-not ~pred ~...@body)) ` -- Steven E. Harris -- 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: difference between if/when
Richard Newman holyg...@gmail.com writes: Incidentally, I initially didn't know about `when-not` -- I figured that `unless` had simply been omitted -- so I defined: (defmacro unless [pred body] `(when (not ~pred) ~...@body)) I did the same, and then was frustrated enough to dig through the core API documentation. Finding `when-not' was nice, but the name still doesn't work for me. Per your/our macro above, it's not really different enough from `when' and `not' to warrant another name. -- Steven E. Harris -- 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: My first use of cells: hashing
pthatcher pthatc...@gmail.com writes: I coded it up, and I liked the result and thought others might be interested. There are several facilities used in your example that I'd like to look into further. I found the `extend-class' function in the core library, but where are the cell-related functions defined? There's the dataflow library in Clojure contrib¹, but it doesn't have an `update-cell' function or form `'. Where are you finding these? Is there public documentation available? Footnotes: ¹ http://richhickey.github.com/clojure-contrib/dataflow-api.html -- Steven E. Harris -- 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: Code Review: how can I make this socket code more functional?
i'm interested in seeing how this progresses ... like how you'd spawn handlers asynchronously to service the requests. was thinking about doing this exercise myself at some point. On Tue, Feb 16, 2010 at 4:30 PM, Alan Dipert alan.dip...@gmail.com wrote: Hi Matt, I think what you're looking for is line-seq: http://richhickey.github.com/clojure/clojure.core-api.html#clojure.core/line-seq In your code, if you pass *in* to line-seq, you'll get back a seq of lines (the request headers). Incidentally, I first ran into line-seq in the course of writing a Clojure web server as a first project. You can see line-seq in action on line 52 of this gist, inside the 'handle-request' function: http://gist.github.com/203329 I'm pretty new to Clojure myself so there might be a better way. Hope this helps, Alan Excerpts from Matt Culbreth's message of 2010-02-16 16:17:57 -0500: Hello Group, I'm writing a web server in Clojure and I'd love to have a bit of help on a function I have. This function (and at http://gist.github.com/305909) is used to read the HTTP request from a client and to then act on it: (defn handle-request [in out] (binding [*in* (BufferedReader. (InputStreamReader. in))] (let [client-out (OutputStreamWriter. out)] (loop [lines []] (let [input (read-line)] (if (= (.length input) 0) ;; 0 length line means it's time to serve the resource (println lines) ;; add to the lines vector and keep going ;; note it makes the incoming request reversed (recur (cons input lines The code works fine; I've left out the bit that actually does something and replaced it with a println call. It's not very functional feeling though. The loop/recur and the building of a list seems very imperative to me. I'd much rather use something from clojure.contrib.io, probably using read-lines or something. Thanks for looking and for any suggestions! Matt -- Alan Dipert http://alan.dipert.org -- 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.comclojure%2bunsubscr...@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: Emacs/Slime -- Slime wont eval but *inferior-lisp* will (Help a newbie out)
joseph hirn joseph.h...@gmail.com writes: All seems to be well when I M-x slime, but if I enter (+ 1 2) it just hangs. If I switch to the *inferior-lisp* buffer and type this expression it returns 3 as expected. I have the same problem, as documented here: http://thread.gmane.org/gmane.comp.java.clojure.user/24894/focus=24956 In the *inferior-lisp* buffer, try evaluating the following form: (.. java.lang.management.ManagementFactory (getRuntimeMXBean) (getName)) Does that cause SLIME's REPL to finally connect to Swank? -- Steven E. Harris -- 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: processing two collections
Glen Rubin rubing...@gmail.com writes: How do I take an element from one collection and test for no remainder (e.g. (zero? (mod x y)), when dividing by every element of the second collection, before processing the next item in the first collection? This form checks if every element of the second range is a factor of every element in the first range: , | (let [r2 (range 100 150)] | (every? | #(every? (partial (comp zero? mod) %) r2) | (range 1000 2000))) ` Note that the walk over (range 1000 2000) is the outer one, and the walk over (range 100 150) (r2) is the inner one. -- Steven E. Harris -- 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 Dev Environment
Wilson MacGyver wmacgy...@gmail.com writes: With the latest intelliJ 9.0.1, la clojure now just works. On /one/ of my computers running Windows XP, I find that the REPL doesn't start properly. Tracing IDEA and Java through Process Monitor, it looks as though Java's attempt to open clojure.jar fails when loaded for the REPL, and hence it can't find the required class (clojure.main), even though IDEA can load the same Jar file for other reasons. It's strange and frustrating. -- Steven E. Harris -- 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: Request for Feedback: Improve VimClojure's documentation
i can echo that last reply. I wanted to use clojure and may return to it ... awesome idea. But haven't had ANY luck with dev environments ... VC, included. gone down many blind alleys. It was almost a year ago that I tried, though. perhaps I should try again. On Thu, Feb 11, 2010 at 12:44 PM, Drew Vogel drewpvo...@gmail.com wrote: The result is horrible error messages like the one in the attached screenshot. I don't have a solution to contribute because I've never consistently solved these problems. Good luck with this effort. I'd like to see VC become more accessible. -- 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: Inheriting from IDeref - good idea or bad practise?
James Reeves weavejes...@googlemail.com writes: Would those more knowledgable about Clojure care to weigh in on whether it be a good idea to create a custom class inheriting from IDeref? That's how promise is implemented, but that's supposed to be an internal detail. -- Steven E. Harris -- 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 for system administration
On Fri, Feb 5, 2010 at 12:56 AM, Greg g...@kinostudios.com wrote: A much easier solution is to go with a lisp designed for exactly the task of scripting. Woah! Seems like an understatement. This newLISP looks POWERFUL. Lot's of new stuff to read. Thank you, thank you. I whole-heartedly recommend newLISP for this: http://www.newlisp.org/ Clojure is excellent when you need a powerhouse LISP capable of great feats, but newLISP is far better suited for scripting tasks, it was designed for that. Or you can implement a *nix shell in Clojure. :-p - Greg On Feb 5, 2010, at 12:42 AM, Tim Clemons wrote: Perhaps the solution is to have a *nix shell implemented in Clojure. That would limit the start-up issue to a single initial instance. Then the user can proceed to use regular command-line functionality interspersed with Clojure scripts. Think of it as a hybrid REPL. On Feb 4, 9:35 am, Phil Hagelberg p...@hagelb.org wrote: On Thu, Feb 4, 2010 at 8:33 AM, Stuart Sierra the.stuart.sie...@gmail.com wrote: Clojure can certainly do these things; clojure-contrib contains many file and io-related utilities. But remember that Clojure, like any Java program, takes more time to start up than scripting languages like Perl/Bash/Ruby/Python, so it may be less suitable for programs that you intend to run at the command-line. Also relevant is the fact that launching Clojure from the command-line is very inconvenient compared to scripting languages. If you want something simple you can just put on your path, you'll need to wrap it in a bash (or other language) script anyway to handle the classpath, etc. The combination of startup time and the need to roll your own bash script even for simple things has kept me from wanting to use Clojure as a perlish-replacement. -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.comclojure%2bunsubscr...@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.comclojure%2bunsubscr...@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: Heap implementation in Clojure
i was messing around a while back with this: http://code.google.com/p/jc-pheap/ the algorithms work, but it's probably in a between-state. I wasn't sure what the interface should look like exactly, and I was recently adding support for duplicate keys (but I wasn't sure if I should have two structures or one ... the latter being more of the multimap I'm describing). Oh, and I was starting to work on decreaseKey(), too ... but the runtime is still, likely amortized for that one. I actually had an idea that I'm not sure has ever been done before to make that operation even more baked. Fun stuff. The project does not depend on clojure, but shows clojure code as an example. If I recall, it all works. H, maybe I'll get back into working on it and variations, tho. On Tue, Dec 15, 2009 at 5:16 AM, ataggart alex.tagg...@gmail.com wrote: On Dec 15, 1:49 am, ataggart alex.tagg...@gmail.com wrote: On Dec 14, 5:48 am, Mark Tomko mjt0...@gmail.com wrote: I wrote this implementation of a heap (or priority queue) in pure Clojure: http://pastebin.com/m2ab1ad5a It's probably not of any quality sufficient to be make it to the contrib package, but it seems to work. Any thoughts on how it might be improved? Thanks, Mark Ideally such a collection would be usable with existing functions, e.g. pop, peek. To accomplish that you really need to implement against the expected java interfaces. I've been playing with the deftype/defprotocol stuff in the new branch, so I figured I'd try to apply that to this problem. This is what I came up with: http://gist.github.com/256815 To be clear, my implementation just uses a sorted list, not a true heap tree. -- 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.comclojure%2bunsubscr...@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: Trouble implementing Dijkstra algorithm in Clojure
folks may be interested in this thing I was working on a while back for Dijkstra and Branch and Bound problems: http://code.google.com/p/jc-pheap/. ... I know this was a while ago :) On Tue, Dec 8, 2009 at 11:26 PM, David Brown cloj...@davidb.org wrote: On Tue, Dec 08, 2009 at 03:22:47PM -0800, ataggart wrote: I would be very surprised if getting the first element from a sorted- set wasn't ~O(1). As has been mentioned, it probably isn't if the set is a tree. But, also, usually, in addition to getting the first element, we also are going to want a set without the first element to represent the rest of the data. Both a sorted-set and a priority-queue are probably O(log n) for the first/rest operation, but the constant factor is likely to be quite different. David -- 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.comclojure%2bunsubscr...@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: Promise/Deliver use cases
Jeff Rose ros...@gmail.com writes: Getting with a timeout versus without one is the difference of: ; blocking deref @p ; deref with 100ms timeout (.get (future @p) 100 TimeUnit/MILLISECONDS) But the former just blocks on the promise being delivered, while the latter creates an anonymous function, creates a proxy Future around it, submits it for execution on a separate thread, and then blocks on the function completing and (possibly) yielding a return value. That's much more than a syntactic difference. I tried to rewrite `promise' in terms of an AbstractQueuedSynchronizer so that I could expose timed waits on it, but I got hung up with lack of access to protected methods in the `proxy' macro. -- Steven E. Harris -- 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 Conference Poll
I didn't know this was a vote for location. If it is, DC would work for me. I thought it was more about weekend vs week. I'd agree weekend is better. On Tue, Jan 26, 2010 at 4:09 PM, Joseph Smith j...@uwcreations.com wrote: +1 Lincoln/Omaha Nebraska. :) --- Joseph Smith j...@uwcreations.com (402)601-5443 On Jan 26, 2010, at 2:29 PM, Michel Vollebregt klmn...@gmail.com wrote: +1 for Europe On Jan 26, 12:22 am, mudphone kyle...@gmail.com wrote: +1 Paris On Jan 22, 11:54 pm, Konrad Hinsen konrad.hin...@fastmail.net wrote: On 22 Jan 2010, at 22:15, Wilson MacGyver wrote: I vote let's turn this into a clojure vacation, and hold it in an exotic location. Otherwise, hey, Columbus Ohio is as good as any other city. :) My vote is for Paris, France :-) 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 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.comclojure%2bunsubscr...@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.comclojure%2bunsubscr...@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: newbie question about ns and :require
Raoul Duke rao...@gmail.com writes: so, like, this means i /not/ the only one who finds the whole (whatever you want to call it) include/import syntax kinda crazy? I was expecting even more of a backlash from those who already get it. For now, I only understand it as, There are a lot of options and whichever one you think sounds appropriate is probably the wrong choice. Be prepared to try several times. -- Steven E. Harris -- 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: newbie question about ns and :require
Justin Kramer jkkra...@gmail.com writes: You may find this ns cheatsheet helpful: http://gist.github.com/284277 That is most helpful. What's not helpful is the weird mix of lists and vectors used by these forms. When I finally made it to :rename accepting a map, I had to take a break. -- Steven E. Harris -- 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: Debugging in Clojure
It has confused me since the day I tried to mess around with clojure that this topic isn't brought up more (not that I follow clj regularly) ... so I'm happy to learn that someone added trace capabilities. That said (and I'm not trying to make this a charged statement ... just a way to learn more) I had always thought that one of the key things that made lisp so complete was that programs don't just crash ... that debugging is fully-baked into the *core* of everything. Now, I don't remember much about the debugging capabilities of, say, CL, but my understanding is that *after* a crash, you can interrogate the state of objects. . . .rather than having to preemptively guess at what you may want to know in the future. Trace is better than logging. Logging just seems like a flawed approach (as others have pointed out). I mean, Log4j (or related) is desired in Java so that someone can get more information without a recompile. But in a dynamically run language or in an environment where you aren't just the user of some closed-off code, you may as well just put print statements where you need them. The latter is what I was advised to do in Clojure, and it was a real turn-off for me. Maybe the lack of appeal comes from having to squeeze in that extra do nesting -- or maybe because you then have to go through and remove all that stuff later. Or in the case of logging? you always leave it there, FOREVER. Even if you never end up caring about some state in a production environment!!! So, anyway, it seems to me that folks have been successfully chipping away, borrowing, and improving the cool things about CL for years, but, amazingly, a newb to Lisp like me can still find something unique about CL. Or, at least it seems unique to me this concept of leaving the user suspended in the middle of the execution exactly where it crashes without having to know before-hand that they should have somehow debugged. It's the only language I know of that comes that close to giving you the true state of a program when it crashed. I mean, any time you have to rerun a program, you have to say, I hope I can repeat (or remember) the conditions. But maybe there are things I'm not considering. It seems like an FP-lang ought to be able to handle something like that environment easily. On the other hand, a parallel world could have real troubles bothering to trying to figure out what any of that would mean. I wonder how CL users feel about this issue. Is it a feature they really love or something they wouldn't miss because they never really took advantage of it? On Sun, Jan 24, 2010 at 8:22 AM, Gabi bugspy...@gmail.com wrote: Be careful of deftrace. It has a bug that crashes when the defn'ed funcs have string comment on the top of the func On Jan 23, 7:02 am, ataggart alex.tagg...@gmail.com wrote: On Jan 22, 6:27 pm, Mike Meyer mwm-keyword-googlegroups. 620...@mired.org wrote: On Fri, 22 Jan 2010 17:25:39 -0800 ajay gopalakrishnan ajgop...@gmail.com wrote: I dont mind using println. The problem is that needs to be inside a do or when ... and that is not really part of my code. When the time comes to remove the prints, i need to remove all these do blocks too. I can leave them as it is I guess, but then it is not neat and non-idiomatic. From all the replies, it seems that Debugging is going to be a pain in the Lisp style languages. How do people in Lisp/Scheme debug it? In the REPL. That's a pretty complete debugger, all by itself. In something like SLIME, you get the ability to examine the call stack, etc. while things are running. The trace package just dumps arguments/results of functions while they run. It's a primitive tool, but better than println's in many cases: user it, then use dotrace: user (use 'clojure.contrib.trace) nil user (defn foo [coll] (reduce + coll)) #'user/foo user (defn bar [coll] (map inc coll)) #'user/bar user (dotrace [foo bar] (foo (bar [1 1 1]))) TRACE t7043: (bar [1 1 1]) TRACE t7043: = (2 2 2) TRACE t7044: (foo (2 2 2)) TRACE t7044: = 6 6 user (dotrace [foo +] (foo (bar [1 1 1]))) TRACE t7071: (foo (2 2 2)) TRACE t7072: |(+ 2 2) TRACE t7072: |= 4 TRACE t7073: |(+ 4 2) TRACE t7073: |= 6 TRACE t7071: = 6 6 and so on. mike -- Mike Meyer m...@mired.org http://www.mired.org/consulting.html Independent Network/Unix/Perforce consultant, email for more information. O ascii ribbon campaign - stop html mail -www.asciiribbon.org See, I *knew* there had to be a way to do it! Clearly I wasn't grokking the docs for dotrace. If the authors of of c.c.trace are amenable, I'm inclined to add this functionality to a variant of the c.c.logging/spy macro, something like: (spy [foo bar] (foo (bar [1 1 1]))) -- You received this message because you are subscribed to the Google Groups Clojure group. To
Re: Debugging in Clojure
interesting. thanks for the thoughtful reply. On Sun, Jan 24, 2010 at 2:08 PM, Richard Newman holyg...@gmail.com wrote: That said (and I'm not trying to make this a charged statement ... just a way to learn more) I had always thought that one of the key things that made lisp so complete was that programs don't just crash ... that debugging is fully-baked into the *core* of everything. Now, I don't remember much about the debugging capabilities of, say, CL, but my understanding is that *after* a crash, you can interrogate the state of objects. . . .rather than having to preemptively guess at what you may want to know in the future. This is largely down to CL's condition system: problems are usually reported as conditions, which stop execution without unwinding the stack. Unlike exceptions, you typically get a REPL in the environment of the condition (so you can view locals, inspect objects, etc.) — a bit like being dropped into the debugger in an IDE. Unlike an IDE, you can *do things* to the running program, and the condition often offers restarts (e.g., a compile failed condition might offer to retry the compilation). That means you can fix and continue, or just find out what went wrong. These make an unexpected condition into an interactive process, rather than merely an opportunity for logging. By the time you were ready to ship your app, you'd experienced most of the failures, and introduced static or dynamic handling for those problems. Unfortunately, Java can't match CL's condition system. There are steps towards including some of its power in Clojure (see errorkit). That said, I still use tracing extensively in Common Lisp development: things might not crash, but I still need to see what's going on to identify the root cause of some high-level behavior. I also use print statements: often trace output is too verbose, or I need to see the result of some computation on an intermediate value. Sometimes there's no condition to raise. Trace is better than logging. Logging just seems like a flawed approach (as others have pointed out). I mean, Log4j (or related) is desired in Java so that someone can get more information without a recompile. But in a dynamically run language or in an environment where you aren't just the user of some closed-off code, you may as well just put print statements where you need them. The latter is what I was advised to do in Clojure, and it was a real turn-off for me. Maybe the lack of appeal comes from having to squeeze in that extra do nesting -- or maybe because you then have to go through and remove all that stuff later. Or in the case of logging? you always leave it there, FOREVER. Even if you never end up caring about some state in a production environment!!! I disagree that logging is a flawed approach. Tracing is an interactive tool. Logging allows you to see what happened before you were watching (which is important in the case of systems that are running for months or years, on many different machines, handling millions of requests). It also helps to produce a usable record of events in your program, which aren't always visible in trace output — e.g., this request was invalid because this header appears to be truncated. Try spotting that in trace output. -- 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.comclojure%2bunsubscr...@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
Proxy macro, and calling on a protected method
The documentation for the `proxy' macro mentions lack of access in the defined implementation to protected members: ,[ proxy ] | Note that while method fns can be provided to override protected | methods, they have no other access to protected members, nor to super, | as these capabilities cannot be proxied. ` I just tried to define a proxy that overrides a protected method in the base class, and within that overridden method body attempts to call on some other protected method. It fails, reporting ,[ IllegalArgumentException message prefix ] | No matching field found ` That confirms the warning in the documentation. Is there any other way within Clojure to define a class that does have access to the protected methods of its base class? My motivating example: Writing an AbstractQueuedSynchronizer implementation, which involves a lot of interplay among overridden protected methods and calling on protected methods. -- Steven E. Harris -- 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: Proxy macro, and calling on a protected method
.Bill Smith william.m.sm...@gmail.com writes: you can use java.lang.reflect.Method.setAccessible to make an otherwise protected method available for public access. It looks like one would have to hang on to the Method object and reuse it, as setting one Method instance's accessibility has no influence over /other/ instances of the same Method. Changing the accessibility doesn't seem to have global effect throughout the program. -- Steven E. Harris -- 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: Promise/Deliver use cases
Jeff Rose ros...@gmail.com writes: The future is used because they have a timeout feature when using the .get method. Should there be a corresponding timeout-based `deref' function¹ (deref-within?) for promises? Having to close a function over your @p form and spawn a job on a separate thread seems like way too much work just to get a timeout-based wait on the promise's delivery arriving. Footnotes: ¹ http://richhickey.github.com/clojure/clojure.core-api.html#clojure.core/deref -- Steven E. Harris -- 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: Promise/Deliver use cases
Baishampayan Ghose b.gh...@ocricket.com writes: It would be great if someone pointed out some example usage of promise/deliver. I've used them in cases where I think I need a future, but I don't want to wrap the future around some function just to catch and propagate its result elsewhere. In Clojure, the `future' and `future' call functions include the spawning of the function's execution in another thread. That's really several separate concerns: future = function + promise + async + deliver Exposing `promise' and `deliver' directly allows one to use other means of spawning asynchronous work (or not) while still retaining the block-on-a-latching-result capability. -- Steven E. Harris -- 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: Suggest slime-redirect-inferior-output be default for Swank clojure
Alex Stoddard alexander.stodd...@gmail.com writes: With that all stdout ends up in the repl buffer. I spent hours last weekend working on a rebind-in-other-threads solution, completely forgetting that one can adjust SLIME to handle this problem. Also frustrating: Why don't any of the printing functions accept a Writer or OutputStream as a substitute for *out*? Common Lisp has a nice treatment of these kinds of functions¹: the output stream argument is optional, and, if specified, accepts nil and t as special stream designators² as well. Footnotes: ¹ http://www.lispworks.com/documentation/HyperSpec/Body/f_wr_pr.htm http://www.lispworks.com/documentation/HyperSpec/Body/f_format.htm ² http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_s.htm#stream_designator -- Steven E. Harris -- 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: Lift and bind
jim jim.d...@gmail.com writes: You know, I think you're right. I would refer you to part 2 of Konrad's monad tutorial, but the link is broken. Check google's cache, if you want to read an explanation immediately. That's how I've been reading his tutorials, as WordPress isn't delivering the pages. In A monad tutorial for Clojure programmers (part 2), he writes: , | Perhaps the most frequently used generic monad function is m-lift. It | converts a function of n standard value arguments into a function of n | monadic expressions that returns a monadic expression. ` I take it monadic expression is a synonym for monadic value. I'll have to go change that. Thanks for pointing it out and sorry for any confusion. Well, having caught a conflict, it caused me to look deeper several times until I felt confident enough to ask. Learning was my goal, and your essays have been tremendously helpful. -- Steven E. Harris -- 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
Lift and bind (was: Understanding the continuation monad's bind operator)
Konrad Hinsen konrad.hin...@fastmail.net writes: For a function of a single argument, m-lift and m-fmap are equivalent. In Jim Duey's essay Higher Level Monads¹, he writes the following on the lift operator: ,[ m-lift ] | If you have a function that you would like to turn into a monadic | function, that is a function that can be passed to m-bind, you use | m-lift. | | m-lift takes two parameters, a function to lift and the number of | arguments that function accepts. The argument count is the first | parameter and the function is second. The return value is a function | that can be passed to m-bind. ` Isn't it the case, though, that a lifted function /can't/ be passed to bind, because it's not a monadic function? A lifted function takes monadic values as input, rather than a basic value. Is there some operator that converts a normal function a - b to a monadic function a - m b such that one could adapt a normal function for use in and among some other monadic functions (such as with m-chain)? I'm not sure such a translation is possible for all monads. I considered something like this , | (defn as-monadic-fn [f] | (fn [v] | (m-result (f v ` but it looks too simple. Footnotes: ¹ http://intensivesystems.net/tutorials/monads_201.html -- Steven E. Harris -- 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: SLIME/Swank problem with swank.util.sys/get-pid and RuntimeMXBean
Phil Hagelberg p...@hagelb.org writes: There was some discussion about it a couple months ago: I picked up the torch today, in hope that others will try again for a better resolution: http://thread.gmane.org/gmane.lisp.slime.devel/9178/focus=9383 -- Steven E. Harris -- 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: SLIME/Swank problem with swank.util.sys/get-pid and RuntimeMXBean
Phil Hagelberg p...@hagelb.org writes: If someone would volunteer to fix it, I'd be thrilled. Nobody who is interested in using CL and Clojure at the same time has stepped forward so far, which is why it's currently broken. Can you characterize what needs to be fixed? -- Steven E. Harris -- 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: SLIME/Swank problem with swank.util.sys/get-pid and RuntimeMXBean
Phil Hagelberg p...@hagelb.org writes: Could you try installing SLIME via ELPA as recommended in the swank-clojure readme? That will be a project I'll have to defer until the weekend, as I've never used ELPA. I use the CVS SLIME almost daily for Common Lisp work, so I'm reluctant to give it up. Also, it's not a tenable situation to fork SLIME for Clojure support. CVS head is known to have introduced incompatibilities with Clojure. Is the git repository at git://git.boinkor.net/slime.git just tracking the CVS repository, or is that the same as the ELPA-hosted one? I did try all of this with the git version and found the exact same behavior as with the CVS version. -- Steven E. Harris -- 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: Understanding the continuation monad's bind operator
Thank you, Konrad. Your explanation was perfect. -- Steven E. Harris -- 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: Understanding the continuation monad's bind operator
Konrad Hinsen konrad.hin...@fastmail.net writes: When the monadic values are functions representing computations, monadic composition yields a new function but doesn't execute anything. When the monadic values represent results of computations, then monadic composition implies execution of the computational steps. Can you recommend a book that covers aspects of monads like these? I'd like to learn more about the abstract concepts than their implementation in a particular language. -- Steven E. Harris -- 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: Understanding the continuation monad's bind operator
Konrad Hinsen konrad.hin...@fastmail.net writes: Exactly. The result of m-bind must be a continuation-accepting function again. Yes, and invoking 'mv' yields such a function. That's the role of the outer layer (fn [c] ...). That one adds /another/ layer, but the inner function returned by 'mv' has the same signature, right? It is indeed a value of the right type, but it is not right value that represents the composite computation. Ah, now we're getting somewhere. This version of m-bind would not return the composite computation, but rather execute it immediately. This is best seen by the position of mv. In your m-bind, mv is called when m-bind is called. That's not the desired behaviour. I'm interested in what you mean by composite computation, because I think it's hinting at some concept for monads that I missed. If, as you say, executing the function immediately is not acceptable behavior, then I infer that the goal is to delay evaluation of the monadic function 'f' until someone finally passes in a real continuation as, say, by the `run-cont' function. Is that right? If so, is it the case with all or most monads that the bind operator is not meant to actually perform computation on the spot, but rather to compose a delayed computation, or is this delaying particular to the continuation monad? -- Steven E. Harris -- 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: Understanding the continuation monad's bind operator
jim jim.d...@gmail.com writes: Don't know if you saw, but I did a whole tutorial on the continuation monad. Your essay is how I got started with monads in Clojure. I've read it six times now (along with five other of your essays on the subject), but perhaps I missed the requirement pertaining to delaying evaluation of the monadic function provided to bind. -- Steven E. Harris -- 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: Understanding the continuation monad's bind operator
I have a few more questions concerning how one interacts with a continuation monad. It's clear that a monadic function accepts some base value and returns a monadic value, in turn being a function accepting a single continuation argument. That means that a monadic function has a signature like a - m b Say that we're looking to use some normal functions with this monad. Those functions may have signatures like a - b They clearly don't return the right kind of value. There must be some way to integrate such functions without writing new wrappers around them by hand. Is this a job for `m-fmap'? Reading the implementation, it looks like it would take a normal function and allow it to call on the basic value extracted from a monadic value. The lift operator also sounded relevant, but, if I understand it correctly, it converts a normal function to one that accepts a monadic value and returns a monadic value. That's the wrong argument type to be used with bind -- which wants to call on a monadic function with a basic value -- so I don't understand when one would want to use lift. When would one be able to call on a lifted function? A simple example would help. -- Steven E. Harris -- 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
Understanding the continuation monad's bind operator
In clojure.contrib.monads, there's a monad defined called cont-m to model continuations. Its bind operator -- `m-bind` -- is defined as follows: , | (fn m-bind-cont [mv f] | (fn [c] | (mv (fn [v] ((f v) c) ` I'm curious why there's an extra delaying wrapper function there. The outermost `fn' form taking the argument c as a continuation looks like it serves only to delay evaluation of the remaining forms. The parameter mv is a monadic value which, for the continuation monad, is a function accepting a single continuation argument. The parameter f is a monadic function which, again, for the continuation monad, is a function accepting a value offered by a continuation and returning a monadic value -- another function accepting a single continuation argument. If all of that is true, then the form , | (f v) ` should evaluate to a monadic value and be suitable as a return value from `m-bind'. In short, why is this not an acceptable implementation? , | (fn m-bind-cont [mv f] | (mv (fn [v] (f v ` -- Steven E. Harris -- 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: SLIME/Swank problem with swank.util.sys/get-pid and RuntimeMXBean
Rob Wolfe r...@smsnet.pl writes: Do you use slime-indentation.el in your configuration? Yes. It turns out that I have another Lisp-related initialization file that contained the following form: , | (slime-setup '(slime-fancy |slime-asdf |slime-fontifying-fu |slime-indentation |slime-indentation-fu |slime-banner)) ` Removing the indentation-related entries fixed the `etypecase' Elisp error. Unfortunately, the SLIME-Swank handshake still doesn't complete (and hence the SLIME REPL doesn't start up) without the aforementioned prodding. -- Steven E. Harris -- 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: SLIME/Swank problem with swank.util.sys/get-pid and RuntimeMXBean
Phil Hagelberg p...@hagelb.org writes: But I'm not quite following on the exact problem and specific repro case; could you clarify? Yes. When I start SLIME, the Swank back-end starts and presents the Clojure REPL in the *inferior-lisp* buffer. Right after that, the SLIME front-end sends an Emacs REX command to the Swank back-end, asking it to invoke the `connection-info' function. At this point, the SLIME front-end has reported that it's trying to connect. The Swank back-end receives the REX request, invokes the `connection-info' method on some thread separate from the thread servicing the Clojure REPL, and hangs in its call to `get-pid'. Because the Swank back-end thread servicing the call to `connection-info' hasn't responded, the SLIME front-end is hung waiting for its REX to complete to gather the `connection-info' result. Not until the SLIME front-end has received that result will it finally announce that it succeeded connecting and present the SLIME REPL. It's not just the SLIME REPL that won't work until that `connection-info' REX completes. Any buffers that attempt to submit forms to Clojure for evaluation will not receive a result; the requests are merely queued because the SLIME front-end has not completed its connection and initial handshake. The call to `get-pid' hangs on its call to RuntimeMXBean#getName() which is part of the first path taken by `get-pid': , | (.. java.lang.management.ManagementFactory | (getRuntimeMXBean) | (getName) | (split @)) ` Now, I found a way to unblock that hung call to RuntimeMXBean#getName(): In the Clojure REPL available in the *inferior-lisp* buffer, I can evaluate the following form: , | (.. java.lang.management.ManagementFactory (getRuntimeMXBean) (getName) ` That evaluation takes place in the thread servicing the Clojure REPL, which is a different thread from the one blocked in the REX call to `connection-info' and, transitively, `get-pid'. The above form evaluates immediately in he Clojure REPL and, as a side-effect I don't yet understand, /also/ causes the call blocked in the Swank REX-servicing thread to complete as well. Hence, `get-pid' completes, the `connection-info' completes, then the SLIME front-end receives its reply and finally sets up the SLIME REPL. From then on, all is well. I've been searching the Web looking for similar complaints about such a call hanging, and so far I've come up blank. Again, note that calling ManagementFactory#getRuntimeMXBean() from the Clojure REPL is not sufficient to unblock the other thread hung in `get-pid'; it takes calling RuntimeMXBean#get() -- actually using the RuntimeMXBean instance -- to unblock the other thread. Perhaps there's some lazy initialization going on in Sun's RuntimeMXBean implementation. Does it occur with the latest version of swank-clojure? Yes. I'm tracking the tip of the master branch via Git. Here's the stack: o swank-clojure Git head. o SLIME Both CVS head and git://git.boinkor.net/slime.git head behave the same way, as the offending calls are in swank-clojure. o Clojure 1.1.0 Downloaded Jar from code.google.com. o GNU Emacs 23.1.1 o Windows XP 32-bit -- Steven E. Harris -- 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: SLIME/Swank problem with swank.util.sys/get-pid and RuntimeMXBean
Steven E. Harris s...@panix.com writes: it takes calling RuntimeMXBean#get() -- actually using the RuntimeMXBean instance -- to unblock the other thread. I meant RuntimeMXBean#getName() there. My typing is poor this morning. -- Steven E. Harris -- 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: SLIME/Swank problem with swank.util.sys/get-pid and RuntimeMXBean
Steven E. Harris s...@panix.com writes: In the meantime, I'll continue the investigation. Here are two thread dumps of the Java process running Clojure and Swank, which, at this time, has a live Clojure REPL, but the Swank call to `connection-info' hasn't completed yet. This first one comes via jvisualvm: == 2010-01-02 10:55:39 Full thread dump Java HotSpot(TM) Client VM (14.3-b01 mixed mode, sharing): RMI TCP Connection(4)-192.168.1.35 daemon prio=6 tid=0x02e43000 nid=0x15f8 runnable [0x0377f000] java.lang.Thread.State: RUNNABLE at java.net.SocketInputStream.socketRead0(Native Method) at java.net.SocketInputStream.read(Unknown Source) at java.io.BufferedInputStream.fill(Unknown Source) at java.io.BufferedInputStream.read(Unknown Source) - locked 0x23215700 (a java.io.BufferedInputStream) at java.io.FilterInputStream.read(Unknown Source) at sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source) at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source) at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source) at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source) at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) at java.lang.Thread.run(Unknown Source) Locked ownable synchronizers: - 0x2321c928 (a java.util.concurrent.locks.ReentrantLock$NonfairSync) RMI TCP Connection(idle) daemon prio=6 tid=0x02f74c00 nid=0x121c waiting on condition [0x0372f000] java.lang.Thread.State: TIMED_WAITING (parking) at sun.misc.Unsafe.park(Native Method) - parking to wait for 0x231df420 (a java.util.concurrent.SynchronousQueue$TransferStack) at java.util.concurrent.locks.LockSupport.parkNanos(Unknown Source) at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(Unknown Source) at java.util.concurrent.SynchronousQueue$TransferStack.transfer(Unknown Source) at java.util.concurrent.SynchronousQueue.poll(Unknown Source) at java.util.concurrent.ThreadPoolExecutor.getTask(Unknown Source) at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) at java.lang.Thread.run(Unknown Source) Locked ownable synchronizers: - None JMX server connection timeout 22 daemon prio=6 tid=0x02f70400 nid=0x324 in Object.wait() [0x036df000] java.lang.Thread.State: TIMED_WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on 0x231e31d8 (a [I) at com.sun.jmx.remote.internal.ServerCommunicatorAdmin$Timeout.run(Unknown Source) - locked 0x231e31d8 (a [I) at java.lang.Thread.run(Unknown Source) Locked ownable synchronizers: - None RMI Scheduler(0) daemon prio=6 tid=0x02b4e000 nid=0x1430 waiting on condition [0x0368f000] java.lang.Thread.State: TIMED_WAITING (parking) at sun.misc.Unsafe.park(Native Method) - parking to wait for 0x231b9ae0 (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject) at java.util.concurrent.locks.LockSupport.parkNanos(Unknown Source) at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(Unknown Source) at java.util.concurrent.DelayQueue.take(Unknown Source) at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(Unknown Source) at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(Unknown Source) at java.util.concurrent.ThreadPoolExecutor.getTask(Unknown Source) at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) at java.lang.Thread.run(Unknown Source) Locked ownable synchronizers: - None RMI TCP Connection(idle) daemon prio=6 tid=0x02e4b400 nid=0x1608 waiting on condition [0x0363f000] java.lang.Thread.State: TIMED_WAITING (parking) at sun.misc.Unsafe.park(Native Method) - parking to wait for 0x231df420 (a java.util.concurrent.SynchronousQueue$TransferStack) at java.util.concurrent.locks.LockSupport.parkNanos(Unknown Source) at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(Unknown Source) at java.util.concurrent.SynchronousQueue$TransferStack.transfer(Unknown Source) at java.util.concurrent.SynchronousQueue.poll(Unknown Source) at java.util.concurrent.ThreadPoolExecutor.getTask(Unknown Source) at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) at java.lang.Thread.run(Unknown Source) Locked ownable synchronizers: - None RMI TCP Accept-0 daemon prio=6 tid=0x02b2e800 nid=0x128c runnable [0x035cf000] java.lang.Thread.State: RUNNABLE at java.net.PlainSocketImpl.socketAccept(Native Method) at java.net.PlainSocketImpl.accept(Unknown Source) - locked 0x231cf4e0
Re: SLIME/Swank problem with swank.util.sys/get-pid and RuntimeMXBean
Steven E. Harris s...@panix.com writes: In the meantime, I'll continue the investigation. And yet more information: Apparently it's not critical to call on the RuntimeMXBean#getName() method specifically to kick the Swank thread out of its blocking call; just about /any call on a Java method/ from the Clojure REPL will unblock the Swank thread and make the connection complete. For example, I've tried calling java.util.concurrent.Executors#newSingleThreadExecutor() java.util.Collections#emptySet() java.lang.Math#max() and both work to unblock the Swank thread, but this one does not: java.lang.Integer#parseInt() Now get this: Right before the SLIME-Swank connection completes, Emacs beeps and prints the following two lines in the *Messages* buffer: , | error in process filter: cond: etypecase failed: defun, (number cons string) | error in process filter: etypecase failed: defun, (number cons string) ` Those errors messages come from the ELisp evaluator. Strangely, I can't find any etypecase or typecase form in file slime.el that tolerates all three of those types (number, cons, and string), so it's hard to figure out where the error is arising. -- Steven E. Harris -- 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: SLIME/Swank problem with swank.util.sys/get-pid and RuntimeMXBean
Rich Hickey richhic...@gmail.com writes: Perhaps it would be best to paste such dumps somewhere, rather than mail to the entire list? I'll do that next time. Sorry for the noise. -- Steven E. Harris -- 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: SLIME/Swank problem with swank.util.sys/get-pid and RuntimeMXBean
Steven E. Harris s...@panix.com writes: Now get this: Right before the SLIME-Swank connection completes, Emacs beeps and prints the following two lines in the *Messages* buffer: , | error in process filter: cond: etypecase failed: defun, (number cons string) | error in process filter: etypecase failed: defun, (number cons string) ` I caught the Emacs debugger trace here: http://paste.lisp.org/display/92936 It looks to be a problem parsing the indentation recommendations sent from Swank. -- Steven E. Harris -- 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/SLIME/Emacs questions
Stefan Kamphausen ska2...@googlemail.com writes: you may want to read the thread http://groups.google.com/group/clojure/browse_frm/thread/3e5f416e3f2a1884/337057edae5dcdc3 I had read that thread /twice/ before, as well as the thread on the SLIME mailing list, but I had neglected to try disabling autodoc-mode. This morning, doing so makes things work much better. However, I still notice that when I first run SLIME, the *inferior-lisp* buffer comes up with a responsive REPL, but the SLIME REPL connection is flaky. It takes a long time to finally come through, if it ever does. Perhaps there's some race condition there. Sometimes taking focus away from the Emacs window, doing something, else, and returning to Emacs will cause the SLIME REPL to finally wake up and finish its connection sequence. At that point the animated REPL banner flies out and I have a working REPL. But presentations still don't work. -- Steven E. Harris -- 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/SLIME/Emacs questions
Steven E. Harris s...@panix.com writes: This morning, doing so makes things work much better. Still I see this in the *inferior-lisp* buffer when starting slime: , | (require 'swank.swank) | | (swank.swank/ignore-protocol-version 2009-12-23) | | (swank.swank/start-server c:/DOCUME~1/seh/LOCALS~1/Temp/slime.3420 :encoding iso-latin-1-unix) | | Listening for transport dt_socket at address: | Clojure 1.1.0 | user= | WARNING: reader macro ^ is deprecated; use meta instead | WARNING: reader macro ^ is deprecated; use meta instead | WARNING: reader macro ^ is deprecated; use meta instead | WARNING: reader macro ^ is deprecated; use meta instead | WARNING: reader macro ^ is deprecated; use meta instead | WARNING: reader macro ^ is deprecated; use meta instead | WARNING: reader macro ^ is deprecated; use meta instead | WARNING: reader macro ^ is deprecated; use meta instead | WARNING: reader macro ^ is deprecated; use meta instead | nil | user= user= 2009-12-23 | user= user= Connection opened on local port 3464 | #ServerSocket ServerSocket[addr=0.0.0.0/0.0.0.0,port=0,localport=3464] | user= user= user= ` Note that I'm using Clojure 1.1.0. Could that be the problem? This is within GNU Emacs 23.1.1 on Windows XP. Once that *inferior-lisp* buffer is up, if I run `slime-repl', the REPL may take an arbitrarily long time to finally connect to Swank. And if it does ever connect, and I shut it down via the sayoonara command, I can't get it to start again successfully. -- Steven E. Harris -- 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