Entwined STM V1.0
Hi All, Almost 4 years ago I developed STM with semantic concurrency control for my project at CERN. Main feature of this STM is the TransactionalMap that lets you merge concurrent changes. Library is heavily tested and is very stable. It has been used in production for the past 2 years. Recently I released it on GitHub: http://entwined.koblik.ch (will redirect to https://github.com/CERN-BE/Entwined-STM) Since Entwined STM was designed to be used from Java I wrote a simple facade for it in Clojure that you can load with (require '[cern.entwined.core :as stm]) Entwined STM operates on a memory with a fixed structure, meaning that you have to define what and how many collections you want to have in your STM and this can't be changed after construction. To construct memory with 1 transactional map and 1 transactional queue run this: (def memory (stm/create-memory :map (stm/create-map) :queue (stm/create-queue))) It's impossible to access transactional entities outside of a transaction, to run a transaction you can use intrans macro (stm/intrans memory data (- data :map (.put :key1 value1)) true) (stm/intrans memory data (- data :map (.get :key1))) ;- value1 First line puts [:key1 value1] pair into the map. True at the end of the body tells the memory to commit this transaction. intrans will initiate commit if body returns truthy value. Second line just shows that the change has been committed. A couple more words on the implementation: I used HashMap to implement the TransactionalMap, I copy the backing map for every transaction which may be expensive for some scenarios. Obvious solution would be to use Clojure's persistent map. Commits are eventually serialized and protected with a single lock. If you take a look at the Java source you'll see that Transaction interface has a second method committed that is called when commit is being done. I use this method to write to the hardware knowing that execution order of committed callbacks is the same as the commit order. I would greatly appreciate any feedback and suggestions. If you have any questions don't hesitate to ask here or email me directly. Documentation is still somewhat lacking and I'd be interested to know which parts of it should be improved first. Cheers, Ivan. -- -- 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: Entwined STM V1.0
Great ! Congratulations! How it does compare with Clojure's builtin STM? Thanks. On Sunday, August 18, 2013 10:24:48 AM UTC+2, Ivan Koblik wrote: Hi All, Almost 4 years ago I developed STM with semantic concurrency control for my project at CERN. Main feature of this STM is the TransactionalMap that lets you merge concurrent changes. Library is heavily tested and is very stable. It has been used in production for the past 2 years. Recently I released it on GitHub: http://entwined.koblik.ch (will redirect to https://github.com/CERN-BE/Entwined-STM) Since Entwined STM was designed to be used from Java I wrote a simple facade for it in Clojure that you can load with (require '[cern.entwined.core :as stm]) Entwined STM operates on a memory with a fixed structure, meaning that you have to define what and how many collections you want to have in your STM and this can't be changed after construction. To construct memory with 1 transactional map and 1 transactional queue run this: (def memory (stm/create-memory :map (stm/create-map) :queue (stm/create-queue))) It's impossible to access transactional entities outside of a transaction, to run a transaction you can use intrans macro (stm/intrans memory data (- data :map (.put :key1 value1)) true) (stm/intrans memory data (- data :map (.get :key1))) ;- value1 First line puts [:key1 value1] pair into the map. True at the end of the body tells the memory to commit this transaction. intrans will initiate commit if body returns truthy value. Second line just shows that the change has been committed. A couple more words on the implementation: I used HashMap to implement the TransactionalMap, I copy the backing map for every transaction which may be expensive for some scenarios. Obvious solution would be to use Clojure's persistent map. Commits are eventually serialized and protected with a single lock. If you take a look at the Java source you'll see that Transaction interface has a second method committed that is called when commit is being done. I use this method to write to the hardware knowing that execution order of committed callbacks is the same as the commit order. I would greatly appreciate any feedback and suggestions. If you have any questions don't hesitate to ask here or email me directly. Documentation is still somewhat lacking and I'd be interested to know which parts of it should be improved first. Cheers, Ivan. -- -- 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: Model validation - exceptions as side-effects?
On 18/08/2013 2:00 PM, Alexandr Kurilin a...@kurilin.net wrote: I'd love to know your expert opinion on this, since you wrote Bouncer: say you're in the situation I listed above, where you don't care about nice error handling, you just want to give the caller a 400 if the input is incorrect. Would you still go the route where the validator function returns a list of errors? My concern is that now I have to have additional checks in place in my controller for whether the model save returned a list of errors, which will regardless ultimately result in a 400 status code. Hi Alexandr, I see your point now and I completely agree your API should leak as little as possible, but no less. By that I mean your API should try and help it users - as Christian pointed out. To me, the types of information you would not want leaked are: database names, table names, server host names, software versions etc. Validation errors on the other hand are, in my opinion, crucial when using an API. It's very frustrating to make a request to an API I'm learning and get a 400 back that tells me nothing about what went wrong - making me go read the docs - so the information you're trying to hide would still be available - only in a different medium. In regards to your question though, about how to handle the validations if you don't care about the actual messages, I'd approach it in one of two ways - this is assuming bouncer as the validation library: The first one is the same as before but highlighting you don't care about the validation results: (defn my-fn [my-map] (match (validate my-map) [nil original-map] (send-400) [_ original-map] (save original-map))) ;; bouncer returns nil as the first element of the vector if the validation is successful For the second one, I'll use the function 'valid?' , also from bouncer, which simply returns a boolean - it's meant for the cases where you don't care about the messages: (defn my-fn [my-map] (if (valid? my-map) (save original-map) (send-400))) I hope this is helpful - but I'd encourage you to think about the scenarios where sending back validation errors could be helpful for your API clients Thanks! (BTW, your blog is great, great content) Thank you for the kind words :) Cheers, Leonardo Borges -- -- 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: Entwined STM V1.0
That's really cool. Do you have any performance benchmark between TransactionalMap and java.util.concurrent.ConcurrentHashMap? When should i use these collections instead of java.util.concurrent.* collections? 2013/8/18 Ivan Koblik ivankob...@gmail.com Hi All, Almost 4 years ago I developed STM with semantic concurrency control for my project at CERN. Main feature of this STM is the TransactionalMap that lets you merge concurrent changes. Library is heavily tested and is very stable. It has been used in production for the past 2 years. Recently I released it on GitHub: http://entwined.koblik.ch (will redirect to https://github.com/CERN-BE/Entwined-STM) Since Entwined STM was designed to be used from Java I wrote a simple facade for it in Clojure that you can load with (require '[cern.entwined.core :as stm]) Entwined STM operates on a memory with a fixed structure, meaning that you have to define what and how many collections you want to have in your STM and this can't be changed after construction. To construct memory with 1 transactional map and 1 transactional queue run this: (def memory (stm/create-memory :map (stm/create-map) :queue (stm/create-queue))) It's impossible to access transactional entities outside of a transaction, to run a transaction you can use intrans macro (stm/intrans memory data (- data :map (.put :key1 value1)) true) (stm/intrans memory data (- data :map (.get :key1))) ;- value1 First line puts [:key1 value1] pair into the map. True at the end of the body tells the memory to commit this transaction. intrans will initiate commit if body returns truthy value. Second line just shows that the change has been committed. A couple more words on the implementation: I used HashMap to implement the TransactionalMap, I copy the backing map for every transaction which may be expensive for some scenarios. Obvious solution would be to use Clojure's persistent map. Commits are eventually serialized and protected with a single lock. If you take a look at the Java source you'll see that Transaction interface has a second method committed that is called when commit is being done. I use this method to write to the hardware knowing that execution order of committed callbacks is the same as the commit order. I would greatly appreciate any feedback and suggestions. If you have any questions don't hesitate to ask here or email me directly. Documentation is still somewhat lacking and I'd be interested to know which parts of it should be improved first. Cheers, Ivan. -- -- 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. -- 庄晓丹 Email:killme2...@gmail.com xzhu...@avos.com Site: http://fnil.net Twitter: @killme2008 -- -- 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: core.async - handling nils
If you use a singleton sentinel value that is generated privately within the core.async implementation, then the sentinel isn't really a regular value in the sense that it can be created by regular user code. nil, on the other hand, gets used very frequently as a value in regular Clojure code. That's a key reason IMHO why it's better to use a sentinel as a closed channel indicator than nil. On Sunday, 18 August 2013 09:43:34 UTC+8, Ben wrote: A sentinel value also prevents channels from being able to send/receive arbitrary values, without further wrapping. Sent from my iPhone On Aug 17, 2013, at 5:48 PM, Mikera mike.r.an...@gmail.com javascript: wrote: My overall sense is that the convenience of using if-let directly in a few use cases doesn't justify making channels fall short of being able to send arbitrary values (nil specifically, and clearly boolean false can cause some problems too). I think it would be a much better design to have a sentinel value and a couple of specialised functions or macros that can detect / interact with it appropriately. With a sentinel value the key part of your if-recv code could just be something like: `(let [~name (! ~port)] (if (end-of-stream? ~name) ~else ~then I can see that wrappers for nil values could also work, but that seems to be a more complex solution (and also potentially with more overhead) than a sentinel value On Saturday, 17 August 2013 07:50:06 UTC+8, Brandon Bloom wrote: I ran into the other half of this problem: If you expect nils to signify closed channels, then you can't leverage the logically false nature of nil without excluding explicit boolean false values. Given the pleasant syntax of if-let / ! pairs, I reworked my early experiments to use if-recv which is defined as follows: (defmacro if-recv Reads from port, binding to name. Evaluates the then block if the read was successful. Evaluates the else block if the port was closed. ([[name port :as binding] then] `(if-recv ~binding ~then nil)) ([[name port] then else] `(let [~name (! ~port)] (if (nil? ~name) ~else ~then I've considered some alternative core.async designs, such as an additional done sentinel value, or a pair of quote/unquote operators (see reduced), but nothing seems as simple as just avoiding booleans and nils, as annoying as that is. I'd be curious to here what Rich team considered and how they're thinking about it. However, my expectation is that the nil approach won't change, since it's pretty much good enough. On Thursday, August 15, 2013 10:44:48 PM UTC-4, Mikera wrote: Hi all, I'm experimenting with core.async. Most of it is exceptionally good, but bit I'm finding it *very* inconvenient that nil can't be sent over channels. In particular, you can't pipe arbitrary Clojure sequences through channels (since sequences can contain nils). I see this as a pretty big design flaw given the ubiquity of sequences in Clojure code - it appears to imply that you can't easily compose channels with generic sequence-handling code without some pretty ugly special-case handling. Am I missing something? Is this a real problem for others too? If it is a design flaw, can it be fixed before the API gets locked down? -- -- You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clo...@googlegroups.com javascript: Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+u...@googlegroups.com javascript: 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+u...@googlegroups.com javascript:. For more options, visit https://groups.google.com/groups/opt_out. -- -- You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- 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: Entwined STM V1.0
Thank you! Great question. I couldn't devise a way to merge concurrent changes in a HashMap using Clojure's STM. A while ago I discussed it with Christophe Grand and he had his own idea about how to fix it: [1] and [2]. IIRC Christophe's solution may see a conflict even if there's no real conflict due to stochastic nature of the implementation. I had this use case in my project that functions as a reservation system, I needed a way to add a record into the Map saying that a given device has been reserved by a given user. Since I didn't know all the devices in advance I needed a way to detect conflicts even if Key/Value pair is added for the first time or when it is removed completely. [1] http://clj-me.cgrand.net/2011/10/06/a-world-in-a-ref/ [2] http://clj-me.cgrand.net/2012/09/21/follow-up-a-world-in-a-ref/ On Sunday, August 18, 2013 12:42:23 PM UTC+2, Hussein B. wrote: Great ! Congratulations! How it does compare with Clojure's builtin STM? Thanks. On Sunday, August 18, 2013 10:24:48 AM UTC+2, Ivan Koblik wrote: Hi All, Almost 4 years ago I developed STM with semantic concurrency control for my project at CERN. Main feature of this STM is the TransactionalMap that lets you merge concurrent changes. Library is heavily tested and is very stable. It has been used in production for the past 2 years. Recently I released it on GitHub: http://entwined.koblik.ch (will redirect to https://github.com/CERN-BE/Entwined-STM) Since Entwined STM was designed to be used from Java I wrote a simple facade for it in Clojure that you can load with (require '[cern.entwined.core :as stm]) Entwined STM operates on a memory with a fixed structure, meaning that you have to define what and how many collections you want to have in your STM and this can't be changed after construction. To construct memory with 1 transactional map and 1 transactional queue run this: (def memory (stm/create-memory :map (stm/create-map) :queue (stm/create-queue))) It's impossible to access transactional entities outside of a transaction, to run a transaction you can use intrans macro (stm/intrans memory data (- data :map (.put :key1 value1)) true) (stm/intrans memory data (- data :map (.get :key1))) ;- value1 First line puts [:key1 value1] pair into the map. True at the end of the body tells the memory to commit this transaction. intrans will initiate commit if body returns truthy value. Second line just shows that the change has been committed. A couple more words on the implementation: I used HashMap to implement the TransactionalMap, I copy the backing map for every transaction which may be expensive for some scenarios. Obvious solution would be to use Clojure's persistent map. Commits are eventually serialized and protected with a single lock. If you take a look at the Java source you'll see that Transaction interface has a second method committed that is called when commit is being done. I use this method to write to the hardware knowing that execution order of committed callbacks is the same as the commit order. I would greatly appreciate any feedback and suggestions. If you have any questions don't hesitate to ask here or email me directly. Documentation is still somewhat lacking and I'd be interested to know which parts of it should be improved first. Cheers, Ivan. -- -- 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: Entwined STM V1.0
I'll come back to you with the benchmarks, so far I haven't done any. I have an impression that ConcurrentHashMap will outperform TransactionalMap in most cases, but there may be cases when different keys end up in the same bucket in the ConcurrentHashMap and that is where TransactionalMap may be faster. To answering your second question: I would use STM only when there's a need to perform a series of coordinated actions. To read a key/value pair and depending on the value update some other transactional entity. For example if I expand on the example posted here: https://github.com/CERN-BE/Entwined-STM/blob/master/src/test/java/cern/entwined/demo/clojure_examples.clj I can write a function that would access map and the queue in the same transaction: (defn add-user-and-queue-update! Adds user and schedules initial update only if it's a new user. [id user update-fn] (intrans memory _ (when-not (get-user id) (add-user id name) (schedule-task update-fn Transactions in Entwined are composable and in the example above I create outer transaction that uses API from the example namespace to check for a condition and only if it is true preform some action. If user is added concurrently than this transaction is restarted and no action is performed. On Sunday, August 18, 2013 1:01:53 PM UTC+2, dennis wrote: That's really cool. Do you have any performance benchmark between TransactionalMap and java.util.concurrent.ConcurrentHashMap? When should i use these collections instead of java.util.concurrent.* collections? 2013/8/18 Ivan Koblik ivank...@gmail.com javascript: Hi All, Almost 4 years ago I developed STM with semantic concurrency control for my project at CERN. Main feature of this STM is the TransactionalMap that lets you merge concurrent changes. Library is heavily tested and is very stable. It has been used in production for the past 2 years. Recently I released it on GitHub: http://entwined.koblik.ch (will redirect to https://github.com/CERN-BE/Entwined-STM) Since Entwined STM was designed to be used from Java I wrote a simple facade for it in Clojure that you can load with (require '[cern.entwined.core :as stm]) Entwined STM operates on a memory with a fixed structure, meaning that you have to define what and how many collections you want to have in your STM and this can't be changed after construction. To construct memory with 1 transactional map and 1 transactional queue run this: (def memory (stm/create-memory :map (stm/create-map) :queue (stm/create-queue))) It's impossible to access transactional entities outside of a transaction, to run a transaction you can use intrans macro (stm/intrans memory data (- data :map (.put :key1 value1)) true) (stm/intrans memory data (- data :map (.get :key1))) ;- value1 First line puts [:key1 value1] pair into the map. True at the end of the body tells the memory to commit this transaction. intrans will initiate commit if body returns truthy value. Second line just shows that the change has been committed. A couple more words on the implementation: I used HashMap to implement the TransactionalMap, I copy the backing map for every transaction which may be expensive for some scenarios. Obvious solution would be to use Clojure's persistent map. Commits are eventually serialized and protected with a single lock. If you take a look at the Java source you'll see that Transaction interface has a second method committed that is called when commit is being done. I use this method to write to the hardware knowing that execution order of committed callbacks is the same as the commit order. I would greatly appreciate any feedback and suggestions. If you have any questions don't hesitate to ask here or email me directly. Documentation is still somewhat lacking and I'd be interested to know which parts of it should be improved first. Cheers, Ivan. -- -- You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clo...@googlegroups.comjavascript: Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+u...@googlegroups.com javascript: 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+u...@googlegroups.com javascript:. For more options, visit https://groups.google.com/groups/opt_out. -- 庄晓丹 Email:killm...@gmail.com javascript: xzh...@avos.comjavascript: Site: http://fnil.net Twitter: @killme2008 -- -- You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to
Help to morph this imperative snippet into a functional one
Hi! 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; } } Thanks for help and time. -- -- 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: Current state of the art in Web deployment?
On Sat, Aug 17, 2013 at 3:52 PM, John Jacobsen eigenhom...@gmail.comwrote: So, what do all y'all do? What is a good lightweight but robust way to get a fairly simple Compojure/Ring app backed by Datomic facing the outside world? Not too worried about massive scalability at this point; simplicity will be a plus (am worried that e.g. Immutant / JBoss are too heavyweight). If simplicity is the goal, then Immutant makes things pretty extremely easy while giving you some infrastructure to build on going forward. Our non-immutant deployment uses a custom jetty startup along with an uberjar build. Doing the uberjar lets us not worry about dependency resolution at deploy time, but that's really it. (I don't know if lein has some other mechanism for fixing dependencies or if the recommendation is to run your own internal caching maven proxy) Other than that, mechanically our deploy is not significantly different from a lein ring server, so maybe you can explain what your concerns with that are? -- -- 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
Can you explain what the code is supposed to do in English? Java is a little hard to read. :-) Are you doing Huffman coding or similar? On 18 August 2013 16:51, Hussein B. hubaghd...@gmail.com wrote: Hi! 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; } } Thanks for help and time. -- -- 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. -- -- 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
It might be Huffman coding but I don't know Hoffman coding in depth, so I can't be precise. :) But any way, it is a snippet written in an imperative style that I'm trying to transfer into a functional one. The amount of mutation and the if statements are blocking me from doing it in Clojure. On Sunday, August 18, 2013 4:27:43 PM UTC+2, Chris Ford wrote: Can you explain what the code is supposed to do in English? Java is a little hard to read. :-) Are you doing Huffman coding or similar? On 18 August 2013 16:51, Hussein B. hubag...@gmail.com javascript:wrote: Hi! 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; } } Thanks for help and time. -- -- You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clo...@googlegroups.comjavascript: Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+u...@googlegroups.com javascript: 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+u...@googlegroups.com javascript:. For more options, visit https://groups.google.com/groups/opt_out. -- -- You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- 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
This is close, though it only permits values at leaves and stores the values in the reverse order. Depending on what you need, this might be sufficient: (defn insert [container letters value] (update-in container letters #(conj % value))) e.g. (- {} (insert foo 3) (insert foo 4) (insert bar 7)) If you do need values at non-leaf notes, you just need a slightly more sophisticated representation. On 18 August 2013 17:38, Hussein B. hubaghd...@gmail.com wrote: It might be Huffman coding but I don't know Hoffman coding in depth, so I can't be precise. :) But any way, it is a snippet written in an imperative style that I'm trying to transfer into a functional one. The amount of mutation and the if statements are blocking me from doing it in Clojure. On Sunday, August 18, 2013 4:27:43 PM UTC+2, Chris Ford wrote: Can you explain what the code is supposed to do in English? Java is a little hard to read. :-) Are you doing Huffman coding or similar? On 18 August 2013 16:51, Hussein B. hubag...@gmail.com wrote: Hi! 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; } } Thanks for help and time. -- -- You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clo...@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+u...@**googlegroups.com For more options, visit this group at http://groups.google.com/**group/clojure?hl=enhttp://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+u...@**googlegroups.com. For more options, visit https://groups.google.com/**groups/opt_outhttps://groups.google.com/groups/opt_out . -- -- You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- 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. -- -- 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
Here's a version that allows values to be anywhere in the tree: (defn insert [[container values] [letter letters] value] (if letter [(update-in container [letter] #(insert % letters value)) values] [container (conj values value)])) e.g. (- [{} []] (insert foo 4) (insert f 5) (insert bar 8)) On 18 August 2013 18:03, Chris Ford christophertf...@gmail.com wrote: This is close, though it only permits values at leaves and stores the values in the reverse order. Depending on what you need, this might be sufficient: (defn insert [container letters value] (update-in container letters #(conj % value))) e.g. (- {} (insert foo 3) (insert foo 4) (insert bar 7)) If you do need values at non-leaf notes, you just need a slightly more sophisticated representation. On 18 August 2013 17:38, Hussein B. hubaghd...@gmail.com wrote: It might be Huffman coding but I don't know Hoffman coding in depth, so I can't be precise. :) But any way, it is a snippet written in an imperative style that I'm trying to transfer into a functional one. The amount of mutation and the if statements are blocking me from doing it in Clojure. On Sunday, August 18, 2013 4:27:43 PM UTC+2, Chris Ford wrote: Can you explain what the code is supposed to do in English? Java is a little hard to read. :-) Are you doing Huffman coding or similar? On 18 August 2013 16:51, Hussein B. hubag...@gmail.com wrote: Hi! 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; } } Thanks for help and time. -- -- You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clo...@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+u...@**googlegroups.com For more options, visit this group at http://groups.google.com/**group/clojure?hl=enhttp://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+u...@**googlegroups.com. For more options, visit https://groups.google.com/**groups/opt_outhttps://groups.google.com/groups/opt_out . -- -- You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- 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. -- -- 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: Current state of the art in Web deployment?
Many thanks to everyone who replied about deploying a Web server to production. Specific replies: On Aug 17, 2013, at 6:51 PM, Mark Mandel mark.man...@gmail.com wrote: On Sun, Aug 18, 2013 at 6:52 AM, John Jacobsen eigenhom...@gmail.com wrote: After some prototyping and development, we are now getting to the stage where lein run and a Jetty server running from -main aren't going to cut it. At the risk of asking a dumb question, but being quite new to Clojure, I don't mind - why do you say they won't cut it? On Aug 18, 2013, at 9:25 AM, Norman Richards o...@nostacktrace.com wrote: Other than that, mechanically our deploy is not significantly different from a lein ring server, so maybe you can explain what your concerns with that are? My main concern was just the need to ssh into the server and run leiningen in the background, as opposed to setting up a real server which starts at boot time. I'm OK w/ wrapping 'lein ring server-headless' with Apache/Nginx, if there are no known issues w/ that approach. On Aug 17, 2013, at 4:52 PM, Ray Miller r...@1729.org.uk wrote: One option is simply to write an upstart script that invokes 'lein ring server-headless' and sit an apache or nginx proxy in front of it. That's how my website is currently running. Alternatively, you could deploy your application as a war to tomcat or jetty. The upstart configuration, which is installed to /etc/init/cms.conf, can be found here: https://gist.github.com/ray1729/6258845 That's very helpful -- can you be a little more specific about what you mean by sit an apache or nginx proxy in front of it? It looks like your example is self-contained (need Clojure/lein + upstart, and that's it). Thanks again everyone. John -- -- 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.
Comparing of 2 words
Hi, I wrote a set of functions to compare 2 words managing the keyboard mistakes. The common mistakes are insertion, deletion, substitution or inversion. It can be useful for searching name, product reference, city For example, if you want to let 2 errors in an input, you can do: ;; a name (candidates? hickey hikey 3) -- true (candidates? hickey hitchock 3) -- false ;; a city (candidates? montrouge monrouge 3) -- true ;; a brand (candidates? google googel 3) -- true I used lazy sequence to avoid compare the words completely if they' re very different. Thus, (candidates? hickey jobs 3) -- returns false when the third error is found. The code is on gist: https://gist.github.com/chrix75/6262565 Christian -- -- 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: Current state of the art in Web deployment?
I don't think there is a such thing as a real server. Any process that listens on a TCP port and talks HTTP is a legitimate server, regardless of when or how it's started up. Upstart is a fine way to run your server and make sure it's restarted if it dies. It's not hacky or unconventional, in fact it's probably the best way. Sitting nginx in front of something usually goes like this: You make your server process listen on some port, but only accepting connections from localhost. Then you make nginx listen on port 80 directly from the internet, and when it receives a request, it forwards it to your server via that internal port on localhost, and returns the results. This extra layer of abstraction gives you a lot of power and flexibility. Of course, you could get fancier than just using localhost, and you might even want several servers running at once, not just one, and round-robin requests to them. But this is the basic idea. And it's the same no matter what language your server is written in, as long as it knows how to talk HTTP over TCP. -Steven On Sun, Aug 18, 2013 at 11:21 AM, John Jacobsen eigenhom...@gmail.comwrote: Many thanks to everyone who replied about deploying a Web server to production. Specific replies: On Aug 17, 2013, at 6:51 PM, Mark Mandel mark.man...@gmail.com wrote: On Sun, Aug 18, 2013 at 6:52 AM, John Jacobsen eigenhom...@gmail.com wrote: After some prototyping and development, we are now getting to the stage where lein run and a Jetty server running from -main aren't going to cut it. At the risk of asking a dumb question, but being quite new to Clojure, I don't mind - why do you say they won't cut it? On Aug 18, 2013, at 9:25 AM, Norman Richards o...@nostacktrace.com wrote: Other than that, mechanically our deploy is not significantly different from a lein ring server, so maybe you can explain what your concerns with that are? My main concern was just the need to ssh into the server and run leiningen in the background, as opposed to setting up a real server which starts at boot time. I'm OK w/ wrapping 'lein ring server-headless' with Apache/Nginx, if there are no known issues w/ that approach. On Aug 17, 2013, at 4:52 PM, Ray Miller r...@1729.org.uk wrote: One option is simply to write an upstart script that invokes 'lein ring server-headless' and sit an apache or nginx proxy in front of it. That's how my website is currently running. Alternatively, you could deploy your application as a war to tomcat or jetty. The upstart configuration, which is installed to /etc/init/cms.conf, can be found here: https://gist.github.com/ray1729/6258845 That's very helpful -- can you be a little more specific about what you mean by sit an apache or nginx proxy in front of it? It looks like your example is self-contained (need Clojure/lein + upstart, and that's it). Thanks again everyone. John -- -- 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. -- -- 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.
ANN Langohr documentation updates
I'm happy to announce that Langohr [1] documentation is being actively worked on again. There's already one full new guide available [2], that covers RabbitMQ extensions and how to use them from Clojure. At least two more guides (TLS/SSL support and Durability) are in the works and will be published in a few days. If you use or in the process of evaluating Langohr, take a look at [2]. It covers quite a few nice features RabbitMQ provides. 1. http://clojurerabbitmq.info 2. http://clojurerabbitmq.info/articles/extensions.html -- MK http://github.com/michaelklishin http://twitter.com/michaelklishin -- -- 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: Current state of the art in Web deployment?
On Sun, Aug 18, 2013 at 9:21 AM, John Jacobsen eigenhom...@gmail.com wrote: My main concern was just the need to ssh into the server and run leiningen in the background, as opposed to setting up a real server which starts at boot time. I'm OK w/ wrapping 'lein ring server-headless' with Apache/Nginx, if there are no known issues w/ that approach. We have a number of processes that we kick off via lein-daemon. We have a standard shell script that mimics standard 'service' operations (start, stop, status, restart) and wraps 'lein daemon ...' commands, and we just symlink it into /etc/init.d to create service files so our processes launch at server startup, and we can stop/start them as needed around deploys. -- Sean A Corfield -- (904) 302-SEAN An Architect's View -- http://corfield.org/ World Singles, LLC. -- http://worldsingles.com/ Perfection is the enemy of the good. -- Gustave Flaubert, French realist novelist (1821-1880) -- -- 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.
Revisiting forward-chaining rules in Clojure
Perhaps the best aspect of Clojure is how it can adopt the best ideas from other domains to concisely solve problems, as we've seen with core.logic, core.async and other libraries. I recently came across a problem domain that is easily expressed in forward-chaining rules, and found Clojure to be a powerful way to solve it. While working through this problem space I started to suspect there is a more general need for forward-chaining rules in Clojure to complement core.logic and other libraries. So as a side project I implemented a raw but working engine to do so. I'm posting here to share a draft of this engine, its major design goals, and to ask for input on how we should approach forward-chaining rules in Clojure in general. The rationale and some examples are on the github page for this enginehttps://github.com/rbrush/clara-rules, which I've tentatively named Clara. The state of the code isn't where it needs to be yet; I've been learning the intricacies of Rete and discovering better ways to solve problems along the way, and some of that is reflected in the code base. However, the major pieces of design and functionality are in place, so I'd like to get input on those. The idea is to draw a bit from Jess and Lisa, with the Java interop strength of Drools, but the advantages and idioms available in Clojure. The major goals are: - Focus on problem spaces naturally expressed as forward-chaining rules. Data-driven needs like eventing, data validation, or application of arbitrary business rules fit here. - Embrace immutability. The rule engine's working memory is a persistent Clojure data structure that can participate in transactions. All changes produce a new working memory that shares state with the previous. - Rule constraints and actions are simply Clojure s-expressions. - First-class Java interoperability and APIs. This should be an alternative to Jess or Drools from Java-land. - Usable either as a library to simplify Clojure code, or as a DSL to externalize business logic. - Working memory facts are typically (but not exclusively) Clojure records or Java objects following the Java Bean conventions. - Support the major advantages of existing rules systems, such as explainability of why a rule fired and automatic truth maintenance. - Collections of facts can be reasoned with using accumulators similar to Jess or Drools. These accumulators leverage the reducers API and are transparently parallelized. - The working memory is independent of the logic flow, and can be replaced with a distributed processing system. A prototype that uses Storm https://github.com/rbrush/clara-storm to apply rules to a stream of incoming events already exists. I'd love to hear thoughts on a couple questions: What else would you want from a forward-chaining rules engine in Clojure? What design changes would you make, given the above criteria and examples on github? All thoughts are appreciated! -Ryan https://github.com/rbrush/clara-rules https://github.com/rbrush/clara-examples https://github.com/rbrush/clara-storm -- -- 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: Current state of the art in Web deployment?
On 18 August 2013 17:21, John Jacobsen eigenhom...@gmail.com wrote: On Aug 17, 2013, at 4:52 PM, Ray Miller r...@1729.org.uk wrote: One option is simply to write an upstart script that invokes 'lein ring server-headless' and sit an apache or nginx proxy in front of it. That's how my website is currently running. Alternatively, you could deploy your application as a war to tomcat or jetty. The upstart configuration, which is installed to /etc/init/cms.conf, can be found here: https://gist.github.com/ray1729/6258845 That's very helpful -- can you be a little more specific about what you mean by sit an apache or nginx proxy in front of it? It looks like your example is self-contained (need Clojure/lein + upstart, and that's it). The Ring server is listening on localhost (port 3000 by default). I've set up an apache reverse proxy that routes requests to the Compojure application. This gives a bit more flexibility e.g. if you have other services on the same machine, or want apache to serve static content directly. Ray. -- -- 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 18 August 2013 12:31, Timo Mihaljov t...@mihaljov.info wrote: 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. :) For the record, I don't like this approach at all. You're creating temporary hash-map's just so you can use the core merge-with function. I prefer to reduce with a custom accumulator function (I think someone already posted something along these lines): (defn accumulate-keys [xs] (reduce (fn [accum [k v]] (assoc accum k (+ v (get accum k 0 {} xs)) Mostly a matter of taste, of course. Ray. -- -- 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: Current state of the art in Web deployment?
Hi John, Building on Ray's answer to use Upstart, I've recently started using a Git-based deployment method that essentially uses a Git post-receive hook to re-deploy the application with a simple git push. To set-up, create a bare repo and a working tree on the deploy host, and the relevant Upstart job. We then deploy using *`git push deployhost:path/to/deploy-repo.git master:deploy`*. When a push is received on the deploy branch, the hook on the remote repo updates the working tree, and restarts the Upstart job. (I use SystemD services in place of Upstart when I get the choice - IMO it beats Upstart hands-down, but that's an aside!) I've put the post-receive hook at https://gist.github.com/james-henderson/6263386 - hope this helps! Regards, James On Sunday, 18 August 2013 17:21:22 UTC+1, John Jacobsen wrote: Many thanks to everyone who replied about deploying a Web server to production. Specific replies: On Aug 17, 2013, at 6:51 PM, Mark Mandel mark@gmail.com javascript: wrote: On Sun, Aug 18, 2013 at 6:52 AM, John Jacobsen eigen...@gmail.comjavascript: wrote: After some prototyping and development, we are now getting to the stage where lein run and a Jetty server running from -main aren't going to cut it. At the risk of asking a dumb question, but being quite new to Clojure, I don't mind - why do you say they won't cut it? On Aug 18, 2013, at 9:25 AM, Norman Richards o...@nostacktrace.comjavascript: wrote: Other than that, mechanically our deploy is not significantly different from a lein ring server, so maybe you can explain what your concerns with that are? My main concern was just the need to ssh into the server and run leiningen in the background, as opposed to setting up a real server which starts at boot time. I'm OK w/ wrapping 'lein ring server-headless' with Apache/Nginx, if there are no known issues w/ that approach. On Aug 17, 2013, at 4:52 PM, Ray Miller r...@1729.org.uk javascript: wrote: One option is simply to write an upstart script that invokes 'lein ring server-headless' and sit an apache or nginx proxy in front of it. That's how my website is currently running. Alternatively, you could deploy your application as a war to tomcat or jetty. The upstart configuration, which is installed to /etc/init/cms.conf, can be found here: https://gist.github.com/ray1729/6258845 That's very helpful -- can you be a little more specific about what you mean by sit an apache or nginx proxy in front of it? It looks like your example is self-contained (need Clojure/lein + upstart, and that's it). Thanks again everyone. John -- -- 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: Revisiting forward-chaining rules in Clojure
Thanks for posting. I will certainly explore this. Did you look at Mimir? https://github.com/hraberg/mimir Could you outline how is Clara's approach different from Mimir? Shantanu On Sunday, 18 August 2013 23:46:14 UTC+5:30, Ryan Brush wrote: Perhaps the best aspect of Clojure is how it can adopt the best ideas from other domains to concisely solve problems, as we've seen with core.logic, core.async and other libraries. I recently came across a problem domain that is easily expressed in forward-chaining rules, and found Clojure to be a powerful way to solve it. While working through this problem space I started to suspect there is a more general need for forward-chaining rules in Clojure to complement core.logic and other libraries. So as a side project I implemented a raw but working engine to do so. I'm posting here to share a draft of this engine, its major design goals, and to ask for input on how we should approach forward-chaining rules in Clojure in general. The rationale and some examples are on the github page for this enginehttps://github.com/rbrush/clara-rules, which I've tentatively named Clara. The state of the code isn't where it needs to be yet; I've been learning the intricacies of Rete and discovering better ways to solve problems along the way, and some of that is reflected in the code base. However, the major pieces of design and functionality are in place, so I'd like to get input on those. The idea is to draw a bit from Jess and Lisa, with the Java interop strength of Drools, but the advantages and idioms available in Clojure. The major goals are: - Focus on problem spaces naturally expressed as forward-chaining rules. Data-driven needs like eventing, data validation, or application of arbitrary business rules fit here. - Embrace immutability. The rule engine's working memory is a persistent Clojure data structure that can participate in transactions. All changes produce a new working memory that shares state with the previous. - Rule constraints and actions are simply Clojure s-expressions. - First-class Java interoperability and APIs. This should be an alternative to Jess or Drools from Java-land. - Usable either as a library to simplify Clojure code, or as a DSL to externalize business logic. - Working memory facts are typically (but not exclusively) Clojure records or Java objects following the Java Bean conventions. - Support the major advantages of existing rules systems, such as explainability of why a rule fired and automatic truth maintenance. - Collections of facts can be reasoned with using accumulators similar to Jess or Drools. These accumulators leverage the reducers API and are transparently parallelized. - The working memory is independent of the logic flow, and can be replaced with a distributed processing system. A prototype that uses Storm https://github.com/rbrush/clara-storm to apply rules to a stream of incoming events already exists. I'd love to hear thoughts on a couple questions: What else would you want from a forward-chaining rules engine in Clojure? What design changes would you make, given the above criteria and examples on github? All thoughts are appreciated! -Ryan https://github.com/rbrush/clara-rules https://github.com/rbrush/clara-examples https://github.com/rbrush/clara-storm -- -- 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: Revisiting forward-chaining rules in Clojure
Shantanu, I appreciate it. I did look at Mimir, but had some different objectives, and therefore tradeoffs, and didn't see a straightforward way to reconcile them. First, I wanted to use existing data models in the rules as is -- be it Clojure records, Java Beans, or other structures. Drools has a number of drawbacks, but has success in Java-land largely because it interoperates with existing models so well. A pure Clojure solution with strong interop could offer a number of advantages over existing engines. In fairness, I have yet to add first-class Java support, but the same structure that uses Clojure records right now will be extended to seamlessly use JavaBeans-style classes. Second, I have a broader goal of executing rules against arbitrarily large data sets in a distributed system, and there are semantic and structural tradeoffs to make that happen. For instance, the underlying working memory is a separate subsystem in Clara, and all join operations are hash-based and structured in such a way that they need not be performed in the same process. The clara-storm project is a very raw proof-of-concept of distributing rules across a cluster, but we should be able to layer it on top of other infrastructures as well, such as Hadoop (although that's another, involved conversation in itself.) At this point I'm more focused on getting the core system correct and useful on its own, doing enough to ensure this will be scalable in the future. There are a number of other distinctions that could probably be reconciled with Mimir's approach, such as the use of Jess- or Drools-like Accumulators to reason over collections of objects. To be honest I didn't look closely on how that could be done given some of the above differences. Thanks! -Ryan On Sunday, August 18, 2013 2:54:32 PM UTC-5, Shantanu Kumar wrote: Thanks for posting. I will certainly explore this. Did you look at Mimir? https://github.com/hraberg/mimir Could you outline how is Clara's approach different from Mimir? Shantanu On Sunday, 18 August 2013 23:46:14 UTC+5:30, Ryan Brush wrote: Perhaps the best aspect of Clojure is how it can adopt the best ideas from other domains to concisely solve problems, as we've seen with core.logic, core.async and other libraries. I recently came across a problem domain that is easily expressed in forward-chaining rules, and found Clojure to be a powerful way to solve it. While working through this problem space I started to suspect there is a more general need for forward-chaining rules in Clojure to complement core.logic and other libraries. So as a side project I implemented a raw but working engine to do so. I'm posting here to share a draft of this engine, its major design goals, and to ask for input on how we should approach forward-chaining rules in Clojure in general. The rationale and some examples are on the github page for this enginehttps://github.com/rbrush/clara-rules, which I've tentatively named Clara. The state of the code isn't where it needs to be yet; I've been learning the intricacies of Rete and discovering better ways to solve problems along the way, and some of that is reflected in the code base. However, the major pieces of design and functionality are in place, so I'd like to get input on those. The idea is to draw a bit from Jess and Lisa, with the Java interop strength of Drools, but the advantages and idioms available in Clojure. The major goals are: - Focus on problem spaces naturally expressed as forward-chaining rules. Data-driven needs like eventing, data validation, or application of arbitrary business rules fit here. - Embrace immutability. The rule engine's working memory is a persistent Clojure data structure that can participate in transactions. All changes produce a new working memory that shares state with the previous. - Rule constraints and actions are simply Clojure s-expressions. - First-class Java interoperability and APIs. This should be an alternative to Jess or Drools from Java-land. - Usable either as a library to simplify Clojure code, or as a DSL to externalize business logic. - Working memory facts are typically (but not exclusively) Clojure records or Java objects following the Java Bean conventions. - Support the major advantages of existing rules systems, such as explainability of why a rule fired and automatic truth maintenance. - Collections of facts can be reasoned with using accumulators similar to Jess or Drools. These accumulators leverage the reducers API and are transparently parallelized. - The working memory is independent of the logic flow, and can be replaced with a distributed processing system. A prototype that uses Storm https://github.com/rbrush/clara-storm to apply rules to a stream of incoming events already exists. I'd love to hear thoughts on a couple
lein-undertow-adapter
I was looking at techempower benchmarks [1] and noticed that fastest (by their measurements) Java HTTP server - Undertow - had no Ring adapter. I felt like it and wrote one just for fun: https://github.com/piranha/ring-undertow-adapter Installation and usage is pretty standard, put [ring-undertow-adapter 0.1.0] in your :dependencies and then you can require it: (require '[ring.adapter.undertow :refer [run-undertow]]) It's fairly simple - that's my first experience in writing a wrapper for Java library and it was an interesting road to walk - no support for websockets or any other async stuff or client. I guess that could be added (or made as a separate library), but right now it's just a Ring adapter. It's certainly faster than Jetty or Netty, and is on par with HTTP-Kit. Enjoy, if you feel like it. [1]: www.techempower.com/benchmarks/ -- -- 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.
[ANN] clj-time 0.6.0 released - some API deprecations
What: A Clojure wrapper for Joda Time Where: https://github.com/clj-time/clj-time Details: An API cleanup that deprecates several inconsistent / abbreviated names and introduces preferred replacements. Deprecated API will remain under 0.7.0 so you will have plenty of time to update your code. Thanx: https://github.com/michaelklishin/ https://github.com/bitemyapp/ aka callen on #clojure freenode -- Sean A Corfield -- (904) 302-SEAN An Architect's View -- http://corfield.org/ World Singles, LLC. -- http://worldsingles.com/ Perfection is the enemy of the good. -- Gustave Flaubert, French realist novelist (1821-1880) -- -- 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: What's your preference, partial or closures?
I prefer to use closures / higher order functions that return a function. Reasons: - You typically get much better performance by returning a closure. partial uses apply, which adds a lot of overhead - It can result in cleaner user code (partials require a bit of mental decoding, and you can give the closure-returning function a good, specific name) On naming, I like to use the er suffix to imply that the return value is a function that will perform the relevant task. e.g. (defn incrementer [value] (fn [x] (+ x value))) ((incrementer 3) 10) = 13 On Saturday, 17 August 2013 06:00:30 UTC+8, nodename wrote: (defn newgrid [m initialize qi qj]... and then (let [init (partial newgrid m initialize)]... Or else: (defn newgrid [m initialize] (fn [qi qj]... and then (let [init (newgrid m initialize)]... -- -- 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: What's your preference, partial or closures?
Am I crazy or does this scream macro? On Saturday, August 17, 2013 6:02:03 PM UTC-7, Sean Corfield wrote: On Sat, Aug 17, 2013 at 5:43 PM, yair yair...@gmail.com javascript: wrote: What do you mean by currying in this context? Is there a way to do this in clojure apart from using partial? (defn some-func ([a b c] (process a b c)) ([a b] (fn [c] (some-func a b c))) ([a] (fn ([b] (fn [c] (some-func a b c))) ([b c] (some-func a b c) (some-func 1 2 3) ((some-func 1 2) 3) (((some-func 1) 2) 3) ((some-func 1) 2 3) -- Sean A Corfield -- (904) 302-SEAN An Architect's View -- http://corfield.org/ World Singles, LLC. -- http://worldsingles.com/ Perfection is the enemy of the good. -- Gustave Flaubert, French realist novelist (1821-1880) -- -- 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: What's your preference, partial or closures?
You're crazy :) On Sun, Aug 18, 2013 at 9:04 PM, Chris Allen callen.2...@gmail.com wrote: Am I crazy or does this scream macro? On Saturday, August 17, 2013 6:02:03 PM UTC-7, Sean Corfield wrote: On Sat, Aug 17, 2013 at 5:43 PM, yair yair...@gmail.com wrote: What do you mean by currying in this context? Is there a way to do this in clojure apart from using partial? (defn some-func ([a b c] (process a b c)) ([a b] (fn [c] (some-func a b c))) ([a] (fn ([b] (fn [c] (some-func a b c))) ([b c] (some-func a b c) (some-func 1 2 3) ((some-func 1 2) 3) (((some-func 1) 2) 3) ((some-func 1) 2 3) -- Sean A Corfield -- (904) 302-SEAN An Architect's View -- http://corfield.org/ World Singles, LLC. -- http://worldsingles.com/ Perfection is the enemy of the good. -- Gustave Flaubert, French realist novelist (1821-1880) -- -- 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. -- Sean A Corfield -- (904) 302-SEAN An Architect's View -- http://corfield.org/ World Singles, LLC. -- http://worldsingles.com/ Perfection is the enemy of the good. -- Gustave Flaubert, French realist novelist (1821-1880) -- -- 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: Revisiting forward-chaining rules in Clojure
On Sunday, August 18, 2013 1:41:56 PM UTC-7, Ryan Brush wrote: Shantanu, I appreciate it. I did look at Mimir, but had some different objectives, and therefore tradeoffs, and didn't see a straightforward way to reconcile them. First, I wanted to use existing data models in the rules as is -- be it Clojure records, Java Beans, or other structures. Drools has a number of drawbacks, but has success in Java-land largely because it interoperates with existing models so well. A pure Clojure solution with strong interop could offer a number of advantages over existing engines. In fairness, I have yet to add first-class Java support, but the same structure that uses Clojure records right now will be extended to seamlessly use JavaBeans-style classes. Second, I have a broader goal of executing rules against arbitrarily large data sets in a distributed system, and there are semantic and structural tradeoffs to make that happen. For instance, the underlying working memory is a separate subsystem in Clara, and all join operations are hash-based and structured in such a way that they need not be performed in the same process. The clara-storm project is a very raw proof-of-concept of distributing rules across a cluster, but we should be able to layer it on top of other infrastructures as well, such as Hadoop (although that's another, involved conversation in itself.) At this point I'm more focused on getting the core system correct and useful on its own, doing enough to ensure this will be scalable in the future. I have been working on a similar approach - only using datomic as the working memory. At one point I briefly considered putting the rete nodes into datomic but quickly realized that wasn't a good idea. The datomic datalog engine is very impressive. I wondered if using that in combination with datomic's tx-report-queue API might be worth looking into - instead of running full queries there could be incremental or persistent queries that yield tuples matching the datalog expressions in a lazy fashion. There are a number of other distinctions that could probably be reconciled with Mimir's approach, such as the use of Jess- or Drools-like Accumulators to reason over collections of objects. To be honest I didn't look closely on how that could be done given some of the above differences. Let me know if you need help. It looks like you are farther along than I am. I agree that clojure is a great medium for a rules engine... I was looking at trying to leverage a lot of the existing match/logic/unification libraries as much as possible but it looks like your engine doesn't rely on them except for core.reducers. You asked about what features I would like to see - does Clara work in the browser/cljs? I haven't tried it yet - do you know any reason why it wouldn't? Alan Thanks! -Ryan On Sunday, August 18, 2013 2:54:32 PM UTC-5, Shantanu Kumar wrote: Thanks for posting. I will certainly explore this. Did you look at Mimir? https://github.com/hraberg/mimir Could you outline how is Clara's approach different from Mimir? Shantanu On Sunday, 18 August 2013 23:46:14 UTC+5:30, Ryan Brush wrote: Perhaps the best aspect of Clojure is how it can adopt the best ideas from other domains to concisely solve problems, as we've seen with core.logic, core.async and other libraries. I recently came across a problem domain that is easily expressed in forward-chaining rules, and found Clojure to be a powerful way to solve it. While working through this problem space I started to suspect there is a more general need for forward-chaining rules in Clojure to complement core.logic and other libraries. So as a side project I implemented a raw but working engine to do so. I'm posting here to share a draft of this engine, its major design goals, and to ask for input on how we should approach forward-chaining rules in Clojure in general. The rationale and some examples are on the github page for this enginehttps://github.com/rbrush/clara-rules, which I've tentatively named Clara. The state of the code isn't where it needs to be yet; I've been learning the intricacies of Rete and discovering better ways to solve problems along the way, and some of that is reflected in the code base. However, the major pieces of design and functionality are in place, so I'd like to get input on those. The idea is to draw a bit from Jess and Lisa, with the Java interop strength of Drools, but the advantages and idioms available in Clojure. The major goals are: - Focus on problem spaces naturally expressed as forward-chaining rules. Data-driven needs like eventing, data validation, or application of arbitrary business rules fit here. - Embrace immutability. The rule engine's working memory is a persistent Clojure data structure that can participate in transactions. All changes produce a new
Re: Revisiting forward-chaining rules in Clojure
The idea of Datomic as an approach to scalable working memory is interesting. I haven't looked at the mechanics of doing this, but it seems possible since Clara aims to separate the working memory system from the rule logic and Rete network. Also, the approach I've taken here aligns with Datomic's ideals of persistent data structures. I think having multiple working memory implementations makes sense -- the approaches for dealing with distributed event streams, local business logic, and incremental queries over large, long-lived memory likely call for different infrastructures. Datomic seems like a possible candidate to fill at least one of those roles. The problems I've been working on haven't (yet) required persisting the working memory, so my focus has been on in-memory models to this point. As for help on this project, it would be welcome! Right now the code is rough and the documentation nearly absent, but I plan on addressing that in the coming weeks. I am starting to track bugs and enhancements on Github for this project in the interest of transparency and collaboration. If there's a particular item of interest, feel free to log or claim an issue on the project. Regarding ClojureScript: I believe it should be straightforward to get this running in ClojureScript, but I haven't attempted it. There is a small amount of logic specific to the JVM -- the mechanism for identifying the fields that exist in a fact used in the working memory -- but that could be factored out ad a ClojureScript alternative made available. I logged an issue to track that: https://github.com/rbrush/clara-rules/issues/4 On Sunday, August 18, 2013 11:51:46 PM UTC-5, Alan Moore wrote: On Sunday, August 18, 2013 1:41:56 PM UTC-7, Ryan Brush wrote: Shantanu, I appreciate it. I did look at Mimir, but had some different objectives, and therefore tradeoffs, and didn't see a straightforward way to reconcile them. First, I wanted to use existing data models in the rules as is -- be it Clojure records, Java Beans, or other structures. Drools has a number of drawbacks, but has success in Java-land largely because it interoperates with existing models so well. A pure Clojure solution with strong interop could offer a number of advantages over existing engines. In fairness, I have yet to add first-class Java support, but the same structure that uses Clojure records right now will be extended to seamlessly use JavaBeans-style classes. Second, I have a broader goal of executing rules against arbitrarily large data sets in a distributed system, and there are semantic and structural tradeoffs to make that happen. For instance, the underlying working memory is a separate subsystem in Clara, and all join operations are hash-based and structured in such a way that they need not be performed in the same process. The clara-storm project is a very raw proof-of-concept of distributing rules across a cluster, but we should be able to layer it on top of other infrastructures as well, such as Hadoop (although that's another, involved conversation in itself.) At this point I'm more focused on getting the core system correct and useful on its own, doing enough to ensure this will be scalable in the future. I have been working on a similar approach - only using datomic as the working memory. At one point I briefly considered putting the rete nodes into datomic but quickly realized that wasn't a good idea. The datomic datalog engine is very impressive. I wondered if using that in combination with datomic's tx-report-queue API might be worth looking into - instead of running full queries there could be incremental or persistent queries that yield tuples matching the datalog expressions in a lazy fashion. There are a number of other distinctions that could probably be reconciled with Mimir's approach, such as the use of Jess- or Drools-like Accumulators to reason over collections of objects. To be honest I didn't look closely on how that could be done given some of the above differences. Let me know if you need help. It looks like you are farther along than I am. I agree that clojure is a great medium for a rules engine... I was looking at trying to leverage a lot of the existing match/logic/unification libraries as much as possible but it looks like your engine doesn't rely on them except for core.reducers. You asked about what features I would like to see - does Clara work in the browser/cljs? I haven't tried it yet - do you know any reason why it wouldn't? Alan Thanks! -Ryan On Sunday, August 18, 2013 2:54:32 PM UTC-5, Shantanu Kumar wrote: Thanks for posting. I will certainly explore this. Did you look at Mimir? https://github.com/hraberg/mimir Could you outline how is Clara's approach different from Mimir? Shantanu On Sunday, 18 August 2013 23:46:14 UTC+5:30, Ryan Brush wrote: Perhaps the best aspect of Clojure