Re: (= '(java.lang.String) (list java.lang.String)) = false ?
On 10.11.2013 14:03, Dave Tenny wrote: I don't understand why these things aren't equal. user= (= (list java.lang.String) (list (class abc))) true user= (= '(java.lang.String) (list (class abc))) false user= (type '(java.lang.String)) clojure.lang.PersistentList user= (type (list java.lang.String)) clojure.lang.PersistentList user= (list java.lang.String) (java.lang.String) user= '(java.lang.String) (java.lang.String) user= (= *1 *2) false What am I missing? user= (type (first (list java.lang.String))) java.lang.Class user= (type (first '(java.lang.String))) clojure.lang.Symbol -- Timo -- -- 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/groups/opt_out.
Re: Counterclockwise
On 07.09.2013 11:24, Josh Kamau wrote: Please allow me to hijack the thread and ask: Does Counterclockwise allow slurping and barfing? like in emacs ? Yes. See http://code.google.com/p/counterclockwise/wiki/EditorKeyBindingsFeatures -- Timo -- -- 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/groups/opt_out.
Re: Counterclockwise
On 07.09.2013 14:02, Josh Kamau wrote: I am unable to use slurp . I am using latest stable version. does *Ctrl+) S* mean pressing Ctrl+Shift+)+S together ? Shift so that i pick ) and not 9 and so that S is in caps. ) is above 0 on my keyboard, so I can trigger the Slurp Right action like this: press Ctrl, Shift, and 0 simultaneously, release everything, press s. -- Timo -- -- 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/groups/opt_out.
Re: Help to morph this imperative snippet into a functional one
On 18.08.2013 16:51, Hussein B. wrote: Would you please help me transforming this imperative code into functional one? The code is a typical snippet in imperative style. A lot of mutations that I don't even know how to start morphing it to Clojure. class Container { MapString, Container children; String letter; ListString value; } void insert(Container container, String letters, String value) { for (int i = 0; i letters.length; i++) { String letter = new String(letters.chatAt[i]); if (container.children.get(letter) != null) { container = container.children.get(letter); } else { MapContainer childContainer = new HashMap(); container.children.put(letter, childContainer); container = container.children.get(letter); } if (i == letters.length() - 1) { container.values.add(value); break; } } (You don't provide example inputs and outputs for the method, so I may have misunderstood the code. If that's the case please disregard the next paragraph.) This example may be to artificial to be translated into Clojure. What use is it to store strings in a tree keyed by the string's characters? If you know the path to the string, you already know the string itself, and you don't need the tree at all! It is rarely a good idea to directly translate code from one language into a much different one. It may be done, but the end result will not be pretty and it certainly won't be idiomatic. I'm sure you'll get much more helpful responses if you ask a question of the form I need to solve this problem – how can I do it in Clojure? If what you want is to manipulate trees in a purely functional way, you might want to check out the Zipper data structure. [1] You can find it in Clojure's standard library in the namespace `clojure.zip`. [2] [1] http://www.st.cs.uni-saarland.de/edu/seminare/2005/advanced-fp/docs/huet-zipper.pdf [2] http://richhickey.github.io/clojure/clojure.zip-api.html Hope this helps, -- Timo -- -- 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/groups/opt_out.
Re: Help to morph this imperative snippet into a functional one
On 19.08.2013 20:27, Timo Mihaljov wrote: This example may be to artificial to be translated into Clojure. What use is it to store strings in a tree keyed by the string's characters? If you know the path to the string, you already know the string itself, and you don't need the tree at all! Aaand of course I misread the code... I got `letters` and `value` mixed up. Sorry about the noise! -- Timo -- -- 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/groups/opt_out.
Re: vec to map with consolidated vals
On 17.08.2013 08:40, David Chelimsky wrote: Which led me to this: (defn to-consolidated-map [parts] (apply merge-with + (map (partial apply hash-map) parts))) This is exactly what I came up with after reading your first message. Apparently Jay Fields took the same approach. I think it's fair to say that this is the idiomatic solution, now that three people have come to the same result independently. :) -- Timo -- -- 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/groups/opt_out.
Re: filter with a sequence of maps not working
On 07.08.2013 10:58, Tilak Thapa wrote: (defn get-data [ attrs] (let [grps data] (if (empty? attrs) grps (map #(select-keys % attrs) grps (filter #(= (% :id) 7) (get-data :id :b)) Why above expression works but same expression wrapped as function (below) does not work? (defn get-data-by-id [id attrs] always pass :id attribute (filter #(= (:id %) id) (get-data attrs))) (get-data-by-id 3) ;; returns () this is probably ok (?) since :id key is not available (get-data-by-id 3 :id :b) ;; returns () but why this does not work? `get-data-by-id` passes one argument to `get-data`: a sequence of attributes. `get-data-by-id` expects one argument per attribute. Instead of `(get-data attrs)`, use `(apply get-data attrs)`. See http://clojuredocs.org/clojure_core/clojure.core/apply for examples demonstrating the use of `apply`. -- Timo -- -- 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/groups/opt_out.
Re: distinction of defrecord instances in sorted-set-by does not work
On 25.07.2013 11:19, gixxi wrote: Consider the following record definition, a respective record instance as well as a sorted tree set with a custom comparator sorting first the :visited property and the by the :dist property of the record. (defrecord RDistance [node dist visited]) (def d (RDistance. foo 1 0)) (def tree (sorted-set-by (comparator (juxt :visited :dist)) d)) I expect conj d again to the set would change the set, but doing so in the repl results in the set containing two equal elements user= (conj tree d) #{#user.RDistance{:node foo, :dist 1, :visited 0} #user.RDistance{:node foo, :dist 1, :visited 0}} What is the problem? The argument to `comparator` should be a function of two arguments that returns a boolean value: http://clojuredocs.org/clojure_core/1.2.0/clojure.core/comparator -- Timo -- -- 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/groups/opt_out.
Re: map from list of maps
On 26.07.2013 00:34, Brian Craft wrote: Is there a better way to do this, making a map of certain keys from a list of maps? (apply hash-map (mapcat (fn [x] [(x :a) (x :b)]) [{:a blah :b ack} {:a red :b blue}])) {red blue, blah ack} Here's another way: (let [xs [{:a blah, :b ack} {:a red, :b blue}]] (zipmap (map :a xs) (map :b xs))) ;= {red blue, blah ack} -- Timo -- -- 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/groups/opt_out.
Re: Not using dependency injection - how do I share services around?
On 10.05.2013 14:04, Colin Yates wrote: 2) to provide a 'get-ds' accessor which returns a new instance and rely on passing that service along to every function that needs it? For what it's worth, some people in the OO community, most notably Nat Pryce and Steve Freeman of Growing Object-Oriented Software[1] fame, advocate[2][3] this approach over using an IoC container. Option 2 means functions are still pure, but how do you prevent huge lists of services - i.e. if func-a calls func-b which calls func-c and func-c needs service-a then func-a and func-b need to access service-a. Yuck. It also means the main entry point to my application needs to assemble all of these services up in one go. Here's the punchline from [3]: If I later find that I can’t get access to some component that I think I need, that’s not necessarily a bad thing. It’s telling me that I’m introducing a new dependency and sometimes that’s a hint that a component is in the wrong place, or that I’m trying to use it from the wrong place. The coding bump is a design feedback mechanism that I miss when I can just pull objects out of a container. If I do a good job, I should find that, most of the time, I have just the right components at the time that I need them. [1] http://www.growing-object-oriented-software.com/ [2] http://www.natpryce.com/articles/000783.html [3] http://www.higherorderlogic.com/2011/07/is-dependency-injection-like-facebook/ -- Timo -- -- 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/groups/opt_out.
Re: Struggling with encapsulation
On 10.05.2013 14:44, John D. Hume wrote: Assume a queue is your only state and `add` and `clear` are your private fns that take a queue as first argument. (defn new-scheduler [] (let [queue (...)] {:add (partial add queue) :clear (partial clear queue)})) There are several disadvantages to this, however. The biggest in my book is that it achieves your goal, and you're limited in the same way your users are. You can't add behavior to an already created scheduler (unless it's built on adding and clearing). Furthermore, if you dynamically recompile `add` or `clear`, it won't change the behavior of an already created scheduler, since partial has the fns, not the symbols or vars that point at them. (These same disadvantages apply to a reified protocol.) You can make dynamic recompilation work by referring to the vars and not the functions: {:add (partial #'add queue) :clear (partial #'clear queue)} This works because vars implement `IFn` by delegating to the function they contain. -- Timo -- -- 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/groups/opt_out.
Re: idiomatic way to force evaluation of a lazy operation
On 04.05.2013 12:16, Korny Sietsma wrote: What's the idiomatic way to avoid this? The options seem to be either to use (doall (map parse-record records)) or (mapv parse-record records) Is either of these better? The latter is simpler, the former (to me) expresses that you are deliberately forcing non-laziness. Or is there some other alternative? `doall` is idiomatic. As you said, `mapv` tells the reader that you need the result to be a vector (you don't) while leaving implicit the fact that you want to force the evaluation of the sequence, so it's confusing in two ways. If you don't care about the return values of the `save-result!` calls, the best way is to use `doseq` to iterate over the records: (defn parse-and-store [raw-data] (try (save-audit-data! raw-data) (let [records (split-records raw-data) results (map parse-record records)] (doseq [result results] (save-result! result))) (catch Exception e (save-error-data! raw-data e -- Timo -- -- 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/groups/opt_out.
Re: idiomatic way to force evaluation of a lazy operation
On 04.05.2013 13:01, Korny Sietsma wrote: Thanks - I thought doall was probably better than mapv. Incidentally, doseq won't work - if the 5th result throws an exception during parsing, results 1-4 will still be saved, whereas I want the whole operation to abort without saving anything. Ah right, I didn't think of that. I'd still go with `doseq` for the saving (otherwise you'll build up a result collection just to throw it away), just wrap the first `map parse-record` in a `doall`. -- Timo -- -- 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/groups/opt_out.
Re: is intellij idea a good ide for clojure development?
On 29.01.2013 16:32, Jay Fields wrote: On Tue, Jan 29, 2013 at 9:28 AM, Feng Shen shen...@gmail.com wrote: I have programming Clojure for almost 2 years, for a living. This is probably an important part of what answer the OP is looking for. When I was doing Clojure for about 10% of my job IntelliJ was fine. Now that it's 90% of my job, I wouldn't be able to give up emacs go back to IntelliJ. If you're just looking at Clojure as a hobby and you already know IntelliJ, I wouldn't recommend switching. However, if you're going to be programming Clojure almost all of the time, I think emacs is the superior choice. For what it's worth, I switched from Emacs to Eclipse and Counterclockwise for Clojure programming. Laurent's done an excellent job with it, and I even prefer his take on paredit over Emacs's original. I still use Emacs for everything else, but for Clojure I find Counterclockwise to be the superior choice. -- Timo -- -- 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/groups/opt_out.
Re: Need ideas for carving project into namespaces
On Thursday, December 13, 2012 11:43:48 PM UTC+2, puzzler wrote: On Thu, Dec 13, 2012 at 1:31 PM, Timo Mihaljov ti...@mihaljov.infojavascript: wrote: (ns example.patron The patron doesn't have an artistic vision (that's the artist's job), nor does it know how to talk to a graphics API (that's what the canvases are for). What it *does* know is how many triangles and squares we can afford, and where we want them drawn. (:require [example.artist :refer [create-masterpiece] example.canvas :refer [make-canvas]])) (defn commision-a-masterpiece [] (create-masterpiece (make-canvas) 500 1000)) I like this idea of using multimethods to send information from the concrete implementations back to the constructor in the core. But how do the concrete implementations ever get loaded? For example, if you start an empty repl and send the example.patron file to the repl, none of the concrete implementations will get loaded, so make-canvas will fail. Same thing if, for example, you made commission-a-masterpiece into the main function and compiled the whole thing into an executable jar. How do you get around this? You are right, I didn't think this through. Frankly, after sleeping over it, I think that the multimethod trick wasn't a good idea. If your users know which implementation they want, they can just as well instantiate it themselves. And if the factory contains some logic for choosing the correct implementation, it necessarily operates on a closed set of implementations, and shouldn't live in a namespace that's all about the *protocol* and thus about *all the implementations*. I think that the difficulty of partitioning code into namespaces is a design smell warning us of conflated responsibilities. The powerful namespace wrangling tools, such as immigrate, deal with the symptoms and not the cause. We should strive to have cohesive namespaces with clear acyclic dependencies, and we can reach that goal by applying the Single Responsibility Principle to namespace design. Here's another stab at the namespace partitioning, this time without a factory function and assuming there's a need for automatic, intelligent selection of a protocol implementation. - canvas: Protocol definition, functions that operate on any protocol implementation. No dependencies. - svg-canvas: Protocol implementation. Depends on canvas. - png-canvas: Protocol implementation. Depends on canvas. - canvas-selection: Automatic selection of a canvas from a known, closed set of canvases. Depends on svg-canvas and png-canvas. - artist: Draws pictures. Depends on canvas. - patron: Commisions pictures from the artist. Depends on artist. May depend on either canvas-selection or one of the concrete canvas implementations. With this architecture there are no cyclic dependencies, and the users are free to choose between automatic canvas selection, one of the predefined canvas implementations, or a canvas implementation of their own. -- Timo -- 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: Need ideas for carving project into namespaces
On 12.12.2012 02:16, Mark Engelberg wrote: Hi Mark, Here's my take on the problem. I hope you can adapt it to your situation. (ns example.canvas A canvas is an abstract interface to a graphics API. The canvas namespace does not build new functionality on top of the APIs, that's a job for another namespace.) (defprotocol Canvas (draw-triangle [canvas point-a point-b point-c]) (draw-circle [canvas position size])) (defmulti make-canvas-of-type (fn [type] type)) (defn make-canvas ([] (make-canvas-of-type :svg)) ([type] (make-canvas-of-type type))) ;--- (ns example.svg-canvas A canvas that produces SVG images. (:import example.canvas.Canvas) (:require [example.canvas :refer [make-canvas-of-type]])) (defmethod make-canvas-of-type :svg [_] (reify Canvas (comment ...))) ;--- (ns example.png-canvas A canvas that produces PNG images. (:import example.canvas.Canvas) (:require [example.canvas :refer [make-canvas-of-type]])) (defmethod make-canvas-of-type :png [_] (reify Canvas (comment ...))) ;--- (ns example.artist The artist uses a canvas to provide advanced rendering operations. It can work with any canvas you give it, so it doesn't care what kind of different canvases there are. (:require [example.canvas :refer [draw-triangle draw-square]])) (defn create-masterpiece [canvas triangle-budget circle-budget] Bigger budgets = better art! (comment (draw-triangle ...) (draw-circle ...))) ;--- (ns example.patron The patron doesn't have an artistic vision (that's the artist's job), nor does it know how to talk to a graphics API (that's what the canvases are for). What it *does* know is how many triangles and squares we can afford, and where we want them drawn. (:require [example.artist :refer [create-masterpiece] example.canvas :refer [make-canvas]])) (defn commision-a-masterpiece [] (create-masterpiece (make-canvas) 500 1000)) -- Timo -- 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 regarding maps
On 24.09.2012 13:04, Mond Ray wrote: user= wish-lists [{:name WL1, :items [{:name Item 1, :cost 20.0} {:name Item 2, :cost 40.0}]} {:name WL2, :items [{:name Wiggle 1, :cost 20.0} {:name Wiggle 2, :cost 40.0} [:name Item 3 :cost 10.0]]}] user= (assoc-in wish-lists [:name WL1] [:name WL1 :items new-wi]) IllegalArgumentException Key must be integer clojure.lang.APersistentVector.assoc (APersistentVector.java:312) `assoc-in` navigates nested data structures by keys. Like George said, vectors' keys are integer indices, so you'd have to use `[0]` as the path to refer to the first wish list. To navigate the data structure using list names, change your `wish-lists` structure into a map with the names as keys. (def wish-lists {WL1 [{:name Item 1, :cost 20.0} {:name Item 2, :cost 40.0}] WL2 [{:name Wiggle 1, :cost 20.0} {:name Wiggle 2, :cost 40.0}]}) `assoc-in` is for adding new key-value pairs to a map, so it isn't quite what you need to append to the wish list vector. There's a more generic function called `update-in`, which takes a function to update the thing at the end of the path. `conj` appends items to a vector, so that's what you should use as the update function. (update-in wish-lists [WL1] conj {:name Item 3 :cost 10.0}) ;= {WL1 [{:name Item 1, :cost 20.0} {:name Item 2, :cost 40.0} {:name Item 3, :cost 10.0}] WL2 [{:name Wiggle 1, :cost 20.0} {:name Wiggle 2, :cost 40.0}]} Hope this helps, -- Timo -- 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: Behavior of (eval) in different namespaces
On 25.09.2012 23:58, Alex Dowad wrote: Does anyone know what's going on here? user= (let [a 1] (eval 'a)) 1 user= (ns another-ns) nil another-ns= (let [a 1] (eval 'a)) CompilerException java.lang.RuntimeException: Unable to resolve symbol: a in this context, compiling:(NO_SOURCE_PATH:41) I don't see this behavior on Clojure 1.4.0 user= (let [a 1] (eval 'a)) CompilerException java.lang.RuntimeException: Unable to resolve symbol: a in this context, compiling:(NO_SOURCE_PATH:1) -- Timo -- 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: Lightweight lib/way to strip html from text
On 06.09.2012 20:41, jamieorc wrote: Hey all, I'm looking for a lightweight way to strip html from a long String of text and leave just the text. I've come across JSoup, but at over 300kb for the lib, not quite lightweight. Suggestions? I've found Jericho HTML Parser to be fast, robust, and well documented: http://jericho.htmlparser.net/docs/index.html Its TextExtractor class seems to do exactly what you need: http://jericho.htmlparser.net/docs/javadoc/net/htmlparser/jericho/TextExtractor.html http://jericho.htmlparser.net/samples/console/src/ExtractText.java -- Timo -- 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 data structures, and other low-level stuff
On 03/15/2012 09:15 PM, Nic Long wrote: So I guess I'm asking whether anyone can recommend some good primers on data structures, both as they relate to Clojure, but also how they work in the fundamentals - e.g. what exactly is the classic model of an 'array' and how does it work, etc. I have read the various performance commitments for the data-types in Clojure on the .org site but even things like Big O notation are still pretty new to me. I'm sure this stuff is pretty basic for many, but I don't know it and would like to! I'm not afraid of some heavy reading; I'd rather get a really deep and solid grasp of the fundamentals, then a quick surface-level solution. If I'm to develop as a programmer I feel like I need to get looking under the hood as it were, even though I can get by in PHP (for the most part anyway) without this kind of understanding. I can't recommend Sedgewick and Wayne's Algorithms [1] enough. It's not heavy reading at all; I'm amazed at how readable the book is considering the subject matter. In addition to the great writing the algorithms are presented as Java source code, and their operation is visualized, so you have three ways of looking at each algorithm, which really helps to understand them. The book is also excellently structured, only introducing a handful of new concepts at a time, so reading it cover to cover you will very rarely feel out of your depth. [1] http://amzn.com/032157351X -- Timo -- 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: (OTP slightly) - ensuring assumptions about structure of function arguments in dynamic languages
As I understand the problem in your example, you do have a definition for what an Insurable is, but it's implicit: there's no way to check whether an object is insurable and thus no way to check which parts of the code break when the notion of being Insurable changes. Luckily Clojure provides us with the tools needed to make the definition explicit. In your Java example you used an interface to define what an Insurable is. In Clojure you can do the same with a protocol: (defprotocol Insurable (cost-to-replace-with-new [insurable])) (def insurable? (partial satisfies? Insurable)) Whenever you expect to receive an insurable, you can use a precondition to make this assumption explicit, like BG and Meikel suggested: (defn calculate-insurance [ insurables] {:pre [(every? insurable? insurables)]} ...) Note that the Insurable objects are completely abstract; we don't know or care what kind of data structure are used to implement them. This means that we can't build valid Insurables by accident, like you did in your example by calling FuncA to FuncE, but that's a *good* thing, because data structures built like that are very brittle, as you noted. To wrap up the example, here are a two very different implementations of Insurable. Note how everything is modeled in terms of domain concepts instead of maps with keys :x, :y and :z. We manipulate the data structures with completely normal Clojure code, but keep the knowledge of those data structures in one place only instead of spreading it all over the codebase. This makes the code much more robust and amenable to change. (defn make-simple-insurable [cost] {:post [(insurable? %)]} (reify Insurable (cost-to-replace-with-new [_] cost))) (defrecord CompositeInsurable [parts] Insurable (cost-to-replace-with-new [composite-insurable] (- (:parts composite-insurable) (map cost-to-replace-with-new) (reduce + (defn make-composite-insurable [ parts] {:pre [(every? insurable? parts)] :post [(insurable? %)]} (CompositeInsurable. parts)) -- Timo -- You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: Leiningen and Cake
On 12/14/2011 06:37 PM, Timothy Washington wrote: 1) The first is being able to pass many tasks to lein. So I would prefer A. instead of B. * A) lein clean deps * B) lein clean lein deps You can chain commands by separating them with a comma: lein clean, deps -- Timo -- 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: Recreate a hierarchy
On Thu, May 05, 2011 at 05:40:02AM -0700, Steffen wrote: Hello, I'm trying to come up with a way to recreate a directory hierarchy. Entries within zip archives are just flat strings like top/level/file1, but I would like to operate on them hierarchically. So my problem could be stated as: If (restore-hierarchy [[top level file1] [top level file2] [top level2 file3]]) returns {top {level (file1 file2), level2 (file3)}} what does a nice definition of #'restore-hierarchy look like? Sadly my own attempts to hack it are too embarrassing to post them here... Here's my version using `clojure.contrib.map-utils/deep-merge-with`: (use '[clojure.contrib.map-utils :only [deep-merge-with]]) (defn file-path [[first rest]] (if rest {first (file-path rest)} first)) (defn restore-hierarchy [x] (- x (map file-path) (apply deep-merge-with list))) Syntax highlighted: https://gist.github.com/957202 -- Timo -- 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: better error messages smaller stack traces
On Tue, Feb 08, 2011 at 09:01:38AM -0500, Stuart Halloway wrote: Please let us know when you get a misleading error message from a macroexpansion, so we can make it better. Or contribute a patch along the lines of [2]. Here's another error message that really threw me off for a while. I have some code that looks like this: (let [[x y] (nth @my-atom z)] ...) Which occasionally failed with: java.lang.UnsupportedOperationException: nth not supported on this type: Float at clojure.lang.RT.nthFrom(RT.java:815) ~[clojure-1.2.0.jar:na] at clojure.lang.RT.nth(RT.java:765) ~[clojure-1.2.0.jar:na] I tried to figure out how a single float could have ended up in that atom and why I couldn't catch it by checking for `(coll? @my-atom)`. After a while I found out that `@my-atom` indeed contained a collection -- a collection of floats -- and that the exception was thrown by the destructuring. An error message something like this would have been much more helpful: Can't destructure `(nth @my-atom z)` to `[x y]`: expected a collection with 2 or more items but got `Float`. -- Timo -- 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: better error messages smaller stack traces
On Tue, Feb 08, 2011 at 09:01:38AM -0500, Stuart Halloway wrote: Please let us know when you get a misleading error message from a macroexpansion, so we can make it better. Or contribute a patch along the lines of [2]. Here's a misleading lack of an error message: (defn foo [x] {:pre (odd? x)} x) The code may look fine at a glance, but the precondition is not wrapped in a seq, so the actual preconditions become checks for truthiness of `odd?` and `x`. Maybe precondition forms should be required to be vectors, so that function call forms can't be mistaken for lists of preconditions? -- Timo -- 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: Images in autodoc?
On Tue, Oct 26, 2010 at 02:15:21PM -0400, Andrew Gwozdziewycz wrote: Areas likely to include gobbledegook: [...] 2. links (internal. for external links, just use fully qualified URI) Internal links could be easily handled by trying to resolve all `code blocks` with ns-resolve in the namespace containing the docstring. If the block resolves to a var, make it a link. No gobbledegook needed. (In practice you'd need a slightly more complicated algorithm to handle cases where e.g. a parameter shadows an existing var.) If you wanted to get real fancy, you could even check if the code block is a list, and then resolve each symbol inside the list, so that, for example, resolve's docstring would look like this at the REPL: user= (doc resolve) - clojure.core/resolve ([sym]) same as `(ns-resolve *ns* sym)` But in the HTML documentation `ns-resolve` and `*ns*` would be hyperlinks. -- Timo -- 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: Game development in Clojure
On Mon, Aug 16, 2010 at 03:43:11AM -0700, Mike Anderson wrote: 2. User interface comes last, which is good in general but makes it a royal pain to pass notifications back to the UI. In Java I would simply have e.g. units.clj call a simple notification function in interface.clj, in Clojure I can't do that because I can't mutually require the namespaces so I end up either passing a callback function or polling some atom, neither of which are particularly elegant. It's often helpful to have one component that acts as a message bus between the other components. A quick and dirty example: ;;; -- ;;; The message bus (ns game.event) ;; A map storing the functions that should be called when an event ;; occurs (def callbacks (atom {})) ;; Functions for subscribing to, and dispatching events (defn call-when [event callback] ...) (defn dispatch [event args] ...) ;;; -- ;;; User interface (ns game.ui (:require [game.event :as event])) ;; An example of an event listener (event/when :unit-destroyed (fn [unit] (comment Update the UI here))) ;; An example of an event dispatcher. Sends an event to be handled by ;; the component whose responsibility it is. Note that at this point ;; we don't know which component that is. (defn request-reinforcements-button-clicked [] (let [amount (.getValue reinforcements-amount-input-field)] (event/dispatch :reinforcements-requested amount))) ;;; -- I've found this approach to work quite well in game development. As the components don't care about who reacts to the messages they send, or who sent the messages they are interested in, it's very easy to plug in and remove components as needed. For example, you can add a sound component that plays appropriate sounds when events occur in the game without requiring any changes to any other components. This approach is especially helpful when unit testing. You can create a new bus and plug in just the component under test, and then simulate all the other components by sending the same messages as they do. -- Timo -- 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
Self-referencing map literals
When defining a map literal, is it possible to reference the map that is being defined? I have some code that looks like this: (let [radius 20 diameter (* 2 radius) circumference (* pi diameter)] {:radius radius :diameter diameter :circumference circumference}) I would like to simplify it to something like: {:radius 20 :diameter (* 2 (% :radius)) :circumference (* pi (% :diameter))} where % is the map itself. Is this possible with the {}-syntax, or is there a macro to do this in the standard library or contrib? -- Timo --~--~-~--~~~---~--~~ 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: Self-referencing map literals
On Mon, Aug 31, 2009 at 09:14:38AM -0400, Chas Emerick wrote: You could define your own let-like construct for this: (defmacro letmap [[m kvs mkvs] body] (if m `(let [~m {} ~@(mapcat (fn [[k v]] `(~m (assoc ~m ~k ~v))) kvs)] (letmap ~mkvs ~...@body)) `(do ~...@body))) Usage: (letmap [a-map {:a 12 :b (* 2 (:a a-map))} another-map {:c (:a a-map) :d (+ (:b a-map) (:c another-map))}] [a-map, another-map]) - [{:b 24, :a 12} {:d 36, :c 12}] Yeah, I needed something like this a while ago, and came up with this: (defmacro let-map Equivalent of (let [a 5 b (+ a 5)] {:a a :b b}). [kvs] (let [keys (keys (apply hash-map kvs)) keyword-symbols (mapcat #(vector (keyword (str %)) %) keys)] `(let [...@kvs] (hash-map ~...@keyword-symbols user= (let-map [a 5 b (inc a) c [a b] d {:foo c :bar (* a b)}]) {:a 5, :c [5 6], :b 6, :d {:foo [5 6], :bar 30}} The nice thing about it is that you no longer need to use all the keywords -- the definition of the map's slots becomes far more like defining sequential bindings in a let. Thank you all for the answers! I especially like Chas's solution. It didn't occur to me that the redundancy can be eliminated by removing the map and leaving in the let -- that's brilliant! :-) It's much easier to read because one doesn't have to dig into the map to get to the variables, and it looks exactly like the common idiom of interdependent let-bindings. -- Timo --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~--~~~~--~~--~--~---
clojure.contrib.test-is/run-tests throws NullPointerException w/ invalid args
When clojure.contrib.test-is/run-tests is given an invalid argument, it throws a NullPointerException: user= (use 'clojure.contrib.test-is) nil user= (run-tests 'asdf) java.lang.RuntimeException: java.lang.NullPointerException (NO_SOURCE_FILE:0) The issue seems harmless in a simple case like this, but in a more complex case the error is quite hard to debug for two reasons: - When the stack trace is longer it's not immediately obvious what caused the NullPointerException. - The error can be caused by a simple typo so it's quite easy to miss when reading the code because the code reads aloud correctly. Having something like 'clojure.contrib.test-is.NamespaceException: No such namespace asdf' would make the source of the error easy to find. I found this bug by having a namespace called errorr (deliberate typo), and accidentally spelled it correctly as error in the argument to run-tests. You might say that I got what I deserved for picking a clever Web2.0 name like that (and I would agree :), but keep in mind that any other typo would have worked and could have been as hard to find. As an example, here's the the stack trace that one typo gave me. Exception in thread main java.lang.RuntimeException: java.lang.NullPointerException (run-tests.clj:0) at clojure.lang.Compiler.eval(Compiler.java:4543) at clojure.lang.Compiler.load(Compiler.java:4857) at clojure.lang.Compiler.loadFile(Compiler.java:4824) at clojure.main$load_script__5833.invoke(main.clj:206) at clojure.main$script_opt__5864.invoke(main.clj:258) at clojure.main$main__5888.doInvoke(main.clj:333) at clojure.lang.RestFn.invoke(RestFn.java:413) at clojure.lang.Var.invoke(Var.java:346) at clojure.lang.AFn.applyToHelper(AFn.java:173) at clojure.lang.Var.applyTo(Var.java:463) at clojure.main.main(main.java:39) Caused by: java.lang.RuntimeException: java.lang.NullPointerException at clojure.lang.LazySeq.seq(LazySeq.java:46) at clojure.lang.RT.seq(RT.java:436) at clojure.core$seq__3133.invoke(core.clj:103) at clojure.core$spread__3240.invoke(core.clj:383) at clojure.core$spread__3240.invoke(core.clj:384) at clojure.core$apply__3243.doInvoke(core.clj:390) at clojure.lang.RestFn.invoke(RestFn.java:443) at clojure.contrib.test_is$run_tests__4789.doInvoke(test_is.clj:914) at clojure.lang.RestFn.invoke(RestFn.java:413) at errorr.engine.gfx.tests$run__7.invoke(tests.clj:5) at user$eval__10.invoke(run-tests.clj:2) at clojure.lang.Compiler.eval(Compiler.java:4532) ... 10 more Caused by: java.lang.NullPointerException at java.util.concurrent.ConcurrentHashMap.get(ConcurrentHashMap.java:768) at clojure.lang.Namespace.find(Namespace.java:129) at clojure.core$find_ns__4309.invoke(core.clj:2347) at clojure.core$the_ns__4321.invoke(core.clj:2371) at clojure.core$ns_name__4325.invoke(core.clj:2376) at clojure.contrib.test_is$fn__4660.invoke(test_is.clj:586) at clojure.lang.MultiFn.invoke(MultiFn.java:157) at clojure.contrib.test_is$test_ns__4785.invoke(test_is.clj:896) at clojure.core$map__3815$fn__3817.invoke(core.clj:1503) at clojure.lang.LazySeq.seq(LazySeq.java:41) ... 21 more -- Timo --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~--~~~~--~~--~--~---
Re: Modifying data structures without changing their interface
Timo Mihaljov wrote: I'm wondering about how to change a data structure without breaking the API used to access it. For example, let's assume that I have a library for dealing with records of people and I'm storing them in structs. (defstruct person :name) The users of my library access the data stored in the records like any other map. (:name some-person) When the library's been in use for a while, I realize that I need to make a change to the data structure. (defstruct :first-name :last-name) The problem is that making this change would break all the clients using the library. After a bit of googling I found what seems to be the perfect solution: http://kotka.de/projects/clojure/lazy-map.html (defn new-person [first-name last-name] (lazy-struct-map person :first-name first-name :last-name last-name :name (str first-name last-name))) This is great news! It means I can develop in Clojure like I did in Python: start out with direct member access and transparently introduce accessors when needed. Yay! :) Now I only wish that de.kotka.lazymap would become a part of Clojure core. -- Timo --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~--~~~~--~~--~--~---
Re: Modifying data structures without changing their interface
Laurent PETIT wrote: While interesting, this approach seems to me limited to simple cases : * limited in possibilities: you are not able to directly use values of other fields. So in more complex cases, you won't be able to combine calculated values without code repetition or prepraration via lets .. * limited in extensibility: in a live system, you won't be able to change the function that displays a name because it's hard-coded once and for all at the same time the data is entered in the system. Depending on your use cases, it may or may not be a problem, though. * limited for persistence: when you want to persist a lazy-struct-map, the computed value is fixed and stored, where it should not be used I think. * limited for equality tests (in relation with limited in extensibility): you will not be able to succesfully compare for equality 2 persons with the exact same essential data, if the way to represent names has been even slightly enhanced, since the :name value will always be used for the comparison as well. So it's not just a problem for performance (very minor in that case, though it may not be that minor in other cases), but also a problem of correctness, in the long run (for systems you want to keep live, and without having to do weird things when you have to marshall / unmarshall your data). Thanks for your insightful reply, Laurent. You are right, lazyseq is indeed too limited to be used in the way I proposed. It's still very cool, though, and I'm sure I'll find some other use for it :) I would like to offer another possibility. Not ideal, maybe, but that may answer your needs. Basically, the idea is that with a language like clojure that has higher order functions and macros, writing boiler plate code should be a code smell. The good news being that in Java, this boiler plate code smell has no solution in some cases (think about design patterns), while with a lisp, you can do something for that. By using a macro, you could generate boiler plate getters for your structure. And just override with new definitions those getter/setters that need computations. The thing that bothers me is that AFAIK there's no standard macro to do this in Clojure. Combined with the facts that spelling out each accessor by hand would be a code smell, and all APIs -- internal or external -- need some form of information hiding to remain stable, I'm left feeling that information hiding should be done in some other way in Clojure. That's why I asked for the idiomatic way to solve the problem in my example. One can write FORTRAN in any language, and I could write any language in Clojure, but I'd rather learn Clojure :) Another issue I have with the accessor function approach is that it can be circumvented very easily by accident because the data structure is exposed to the users of the API. All it takes is typing (:first-name some-person) instead of (first-name some-person), and you get a map lookup instead of a call to a getter. Both forms work as long as the records are maps containing the key :first-name, but the former breaks when the data structure changes. This is especially problematic when wrapping an existing map with accessors -- how can you be sure that you converted each and every key lookup to a getter call? The standard OO approach to information hiding would be private fields and accessor methods. Any suggestions for the One True Clojure Pattern that addresses the same problem? Now that I've read Programming Clojure I know the capabilities of the language. My problem is that I have no idea how to apply them to solve real-world problems, such as the contrived example in my first message. I hope Mr. Halloway starts writing the sequel soon :) -- Timo --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~--~~~~--~~--~--~---
Re: Modifying data structures without changing their interface
Laurent PETIT wrote: What do others think about these 2 above statements ? The standard OO approach to information hiding would be private fields and accessor methods. Any suggestions for the One True Clojure Pattern that addresses the same problem? I think accessor methods. Based on our discussion so far, I would use the following approach. In the spirit of defn-, I appended a dash after field names that should be accessed via accessor functions. This is similar to the Python idiom of prefixing private members with an underscore to prevent _accidental_ direct modification. The symbols are also used as the initial versions of the getter functions. This way there's so little code that no macros are needed. ;;; Initial version ;; Library (defstruct person :full-name-) (defn new-person [full-name] (struct person full-name)) (def full-name :full-name-) ;; Client (def p (new-person James Bond)) (println (full-name p)) ;;; Modified version ;; Library (defstruct person :first-name- :last-name-) (defn new-person [full-name] (let [[first-name last-name] (.split full-name )] (struct person first-name last-name))) (def first-name :first-name-) (def last-name :last-name-) (defn full-name [the-person] (str (first-name the-person) (last-name the-person))) ;; Client (def p (new-person James Bond)) (println (last-name p)) (println (full-name p)) How does this code look like to a experienced Clojure programmer? Does it seem to be in the spirit of the language? -- Timo --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~--~~~~--~~--~--~---
Modifying data structures without changing their interface
Hi, I'm wondering about how to change a data structure without breaking the API used to access it. For example, let's assume that I have a library for dealing with records of people and I'm storing them in structs. (defstruct person :name) The users of my library access the data stored in the records like any other map. (:name some-person) When the library's been in use for a while, I realize that I need to make a change to the data structure. (defstruct :first-name :last-name) The problem is that making this change would break all the clients using the library. The obvious and traditional solution, at least for someone used to thinking in OO terms, would be to tell the clients of the library to treat the records as opaque handles, and only use the library's accessor functions to access their contents. However, I don't like this approach because it leads to a lot of boilerplate code that's there just in case I'll need it some day. It also prevents my clients from using generic map manipulation functions on the records. In Python, my current go-to language, I can have my cake and eat it too by using class properties. # A struct-like class whose members can be manipulated directly class Person1(object): name = full name p1 = Person1() print p1.name # Like above, but with three members, one of which is calculated by # a function when it is accessed class Person2(object): first_name = first last_name = last def get_name(self): return self.first_name + + self.last_name name = property(get_name) p2 = Person2() print p2.name # The old API still works, even though the data is # stored in a different way What's the idiomatic Clojure way of dealing with this issue? -- Timo --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~--~~~~--~~--~--~---
System.loadLibrary() does not work
I'm trying to use Clojure to call a library via JNI. Here's a working piece of Java code that I'm trying to convert to Clojure: import libfoo.Foo; // A GlueGen-generated wrapper class Test { static { System.loadLibrary(foo); // The original library System.loadLibrary(foojni); // A GlueGen-generated wrapper } public static void main(String[] args) { Foo.do_nothing(); } } Here's my Clojure conversion: (import '(libfoo Foo)) (System/loadLibrary foo) (System/loadLibrary foojni) (Foo/do_nothing) Running this Clojure program results in: java.lang.UnsatisfiedLinkError: libfoo.Foo.do_nothing()V (test.clj:0) as if the library wasn't dynamically linked at all. The Clojure code works if I copy the static block from my Java client code into the GlueGen generated Java class, and remove the System/loadLibrary calls from the Clojure client. If the libraries are loaded in the static block of the Java wrapper class, calling System/loadLibrary in Clojure results in: java.lang.UnsatisfiedLinkError: Native Library snip/libfoo.so already loaded in another classloader (test.clj:0) Is there a working equivalent of System.loadLibrary() in the Clojure API? I tried to google for it, but couldn't find anything. Thanks, -- Timo --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~--~~~~--~~--~--~---