(update-in) and getting the new value at the leaf efficiently
Hi, I have this use-case for (update-in) which keeps showing up in my code which I don't have a solution for and I'm wondering if there isn't a solution. How do I _efficiently_ obtain the new value created by an invocation of (update-in), that is, without having to get the modified value by lookups in the new map? Simplified example: (def m {:planet {:country {:state {:city {:borough 4}) (let [mm (update-in m [:planet :country :state :city :borough] (fn [old] (if (nil? old) 0 (inc old] (get-in mm [:planet :country :state :city :borough])) (update-in) returns the new/modified map, but what I want is to obtain the new count returned by the anonymous function. Having to call (get-in) right after is inefficient. This is obviously a contrived example for this question, but I have a lot of real use cases for this (where at the top level of my app I have a ref for a deep structure which changes as a response to network events). Is there an idiomatic way to do this without having to resort to mutability? (The only solution that comes to my mind is to wrap up update-in and the modifier function with a special version that updates a local mutable and return both the new map and the new object.) Nasty? Thank you, -- You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: (update-in) and getting the new value at the leaf efficiently
Here is one way to do it called update-in+. It returns a vector consisting of the new udpated value, like update-in does, followed by the original value (in case you might want to see that for some reason), followed by the updated value. (defn update-in+ ([m [k ks] f args] (if ks (let [[new-map old-val new-val] (apply update-in+ (get m k) ks f args)] [(assoc m k new-map) old-val new-val]) (let [old-val (get m k) new-val (apply f old-val args)] [(assoc m k new-val) old-val new-val] Andy On Thu, Apr 26, 2012 at 9:19 AM, Ambrose Bonnaire-Sergeant abonnaireserge...@gmail.com wrote: Hi, You shouldn't need mutation for such a function. If you look at the source of update-in, it's fairly straightforward. (defn update-in ([m [k ks] f args] (if ks (assoc m k (apply update-in (get m k) ks f args)) (assoc m k (apply f (get m k) args) Just create another function that returns a vector of the result of applying f, and the update-in result. It should be easy starting from update-in's source. (I'm not aware of an existing solution) Thanks, Ambrose On Fri, Apr 27, 2012 at 12:00 AM, blais goo...@furius.ca wrote: Hi, I have this use-case for (update-in) which keeps showing up in my code which I don't have a solution for and I'm wondering if there isn't a solution. How do I _efficiently_ obtain the new value created by an invocation of (update-in), that is, without having to get the modified value by lookups in the new map? Simplified example: (def m {:planet {:country {:state {:city {:borough 4}) (let [mm (update-in m [:planet :country :state :city :borough] (fn [old] (if (nil? old) 0 (inc old] (get-in mm [:planet :country :state :city :borough])) (update-in) returns the new/modified map, but what I want is to obtain the new count returned by the anonymous function. Having to call (get-in) right after is inefficient. This is obviously a contrived example for this question, but I have a lot of real use cases for this (where at the top level of my app I have a ref for a deep structure which changes as a response to network events). Is there an idiomatic way to do this without having to resort to mutability? (The only solution that comes to my mind is to wrap up update-in and the modifier function with a special version that updates a local mutable and return both the new map and the new object.) Nasty? Thank you, -- You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -- You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -- You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: (update-in) and getting the new value at the leaf efficiently
I would have written the fn like this, if I was following what you've been doing: (def m {:planet {:country {:state {:city {:borough 4}) (let [mm (update-in m [:planet :country :state :city :borough ] (fnil inc -1))] (get-in mm [:planet :country :state :city :borough ])) However, when I run into this pattern I usually (let [v ((fnil inc -1) (get-in m [:planet :country :state :city :borough ]))] (assoc-in m [:planet :country :state :city :borough ] v)) The update in does a get, and I do a get-in, so I'm guessing the performance is pretty similar, though I haven't tested it. Cheers, Jay On Thu, Apr 26, 2012 at 12:00 PM, blais goo...@furius.ca wrote: Hi, I have this use-case for (update-in) which keeps showing up in my code which I don't have a solution for and I'm wondering if there isn't a solution. How do I _efficiently_ obtain the new value created by an invocation of (update-in), that is, without having to get the modified value by lookups in the new map? Simplified example: (def m {:planet {:country {:state {:city {:borough 4}) (let [mm (update-in m [:planet :country :state :city :borough] (fn [old] (if (nil? old) 0 (inc old] (get-in mm [:planet :country :state :city :borough])) (update-in) returns the new/modified map, but what I want is to obtain the new count returned by the anonymous function. Having to call (get-in) right after is inefficient. This is obviously a contrived example for this question, but I have a lot of real use cases for this (where at the top level of my app I have a ref for a deep structure which changes as a response to network events). Is there an idiomatic way to do this without having to resort to mutability? (The only solution that comes to my mind is to wrap up update-in and the modifier function with a special version that updates a local mutable and return both the new map and the new object.) Nasty? Thank you, -- You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -- You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: (update-in) and getting the new value at the leaf efficiently
Thanks Andy, Two comments: 1. Your version does not use a transient/mutable, which is great, but it does create one vector for each level. I thought that since this would be wrapped and hidden from external view, a mutable would have been more appropriate. More generally, I still don't know yet where to position myself when I code in Clojure, in terms of performance: I'm used to coding in C where I care a lot about every little detail, like cache coherency, or in Python for glue code where I really don't worry about such minute optimizations. Perhaps I tend to eagerly overoptimize in Clojure? Don't know. I like your version in any case, thank you. 2. More importantly: I don't understand why I'm often having to add some functionality which I think of as something that everyone would need everywhere, and that makes me think I'm thinking about it the wrong way. For example, when I'm being careful about not using any mutable objects anywehre I end up with code that essentially recreates a new path to the root application every time I need to modify/store something in memory (i.e., I get a new version of the world on every update). So I wonder... isn't anybody else in dire need for something like update-in+? How come not? Isn't it a really common case that you need to modify some object far from the root object of your application, and if so, that you may need to do multiple things with that new object, beyond storing it by recreating all the intervening objects? (e.g. (dosync (alter update-in ...))) ) (Generally I find I get too little cultural osmosis when it comes to practical application of Clojure, so questions like this one come up all the time while I'm coding. Meetups and books touch on topics I understand well but rarely do people talk about the kinds of issues I'm encountering, like the one above. Libraries and other people's code often doesn't help all that much because it's fairly easy to do away with mutability in a library context. I'll just read more OPC for now I guess.) -- You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: (update-in) and getting the new value at the leaf efficiently
On Thu, Apr 26, 2012 at 4:30 PM, blais goo...@furius.ca wrote: (Generally I find I get too little cultural osmosis when it comes to practical application of Clojure, so questions like this one come up all the time while I'm coding. Meetups and books touch on topics I understand well but rarely do people talk about the kinds of issues I'm encountering, like the one above. Libraries and other people's code often doesn't help all that much because it's fairly easy to do away with mutability in a library context. I'll just read more OPC for now I guess.) Do you need to represent your data with that much nesting? (def m {:planet ... :country ... :state ... :city ... :borough 4}) What's wrong with this representation? David -- You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: (update-in) and getting the new value at the leaf efficiently
On Thursday, April 26, 2012 4:36:52 PM UTC-4, David Nolen wrote: On Thu, Apr 26, 2012 at 4:30 PM, blais goo...@furius.ca wrote: (Generally I find I get too little cultural osmosis when it comes to practical application of Clojure, so questions like this one come up all the time while I'm coding. Meetups and books touch on topics I understand well but rarely do people talk about the kinds of issues I'm encountering, like the one above. Libraries and other people's code often doesn't help all that much because it's fairly easy to do away with mutability in a library context. I'll just read more OPC for now I guess.) Do you need to represent your data with that much nesting? (def m {:planet ... :country ... :state ... :city ... :borough 4}) What's wrong with this representation? Well this was just to simplify my original question; the real application has a root instance that is a networked application class, which contains some list of clients, each of which has a mapping of orders (per exchange / market, this is a trading application) which themselves map to events related to those orders. So it's more like application - client-handler - feed - market - order-id - event. These aren't necessarily pure data classes--some of these may be records with implementations of protocols. I suppose I could elect to move refs for modifiable things towards the leaves, but that seems to me like going against the grain and may have implications for concurrency (there are few but some threads running in parallel in this application). In this specific example of an application tree, where would you recommend the mutable objects be placed? Thanks, -- You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: (update-in) and getting the new value at the leaf efficiently
On Thu, Apr 26, 2012 at 4:52 PM, blais goo...@furius.ca wrote: I suppose I could elect to move refs for modifiable things towards the leaves, but that seems to me like going against the grain and may have implications for concurrency (there are few but some threads running in parallel in this application). In this specific example of an application tree, where would you recommend the mutable objects be placed? Why do you need refs at leaves? David -- You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: (update-in) and getting the new value at the leaf efficiently
On Thursday, April 26, 2012 4:59:31 PM UTC-4, David Nolen wrote: On Thu, Apr 26, 2012 at 4:52 PM, blais goo...@furius.ca wrote: I suppose I could elect to move refs for modifiable things towards the leaves, but that seems to me like going against the grain and may have implications for concurrency (there are few but some threads running in parallel in this application). In this specific example of an application tree, where would you recommend the mutable objects be placed? Why do you need refs at leaves? I receive events from a network. My application calls for storing these events and doing different things based on the changing status of orders attached to these events. I need to store them somewhere, I need to track this state in my app. At one extreme, I could store the changing state near the leaves (i.e. a list of events by order-id by ...). At another extreme, I could recreate the entire path of immutable objects all the way to the root application on every update (using update-in, and with a single ref for the root application). And then there's all the other options in between, I could have refs are every level if I chose to (but that seems very, very wrong, somehow). Java would call for mutability at the leaves. Clojure makes it easy to build it one way or another, but the language is calling for refs at the root. Isn't this a really common case of every type of application out there which has to store some changing state somewhere? -- You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: (update-in) and getting the new value at the leaf efficiently
On Thu, Apr 26, 2012 at 5:08 PM, blais goo...@furius.ca wrote: I receive events from a network. My application calls for storing these events and doing different things based on the changing status of orders attached to these events. I need to store them somewhere, I need to track this state in my app. At one extreme, I could store the changing state near the leaves (i.e. a list of events by order-id by ...). At another extreme, I could recreate the entire path of immutable objects all the way to the root application on every update (using update-in, and with a single ref for the root application). And then there's all the other options in between, I could have refs are every level if I chose to (but that seems very, very wrong, somehow). Java would call for mutability at the leaves. Clojure makes it easy to build it one way or another, but the language is calling for refs at the root. Isn't this a really common case of every type of application out there which has to store some changing state somewhere? You've already stated that your multithreaded needs are modest. Why not one atom wrapping all your data, each piece indexed by the most relevant key, and each actual piece of data is flat. David -- You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en
Re: (update-in) and getting the new value at the leaf efficiently
I think you are too concerned with micro optimizations. get-in is probably just as efficient as attempting to bubble the state change back up and certainly simpler to work with. In practice, optimizations like this do not have a significant impact on the overall performace. Measure before you optimize. I might also add, parrelize before you optimize. Immutable data structures often makes it much easier to parrelize the algorithm, so even if you do have slow spots if the applications critical path is not affected you still may not need to optimize. There probably are several methods in clojure that can be significantly optimized and eventually someone will, but the best optimizations will come from real world performance problems not theoretical ones. Do some research on clojures vector implementation and you'll see the fastest implementation in theory is comparitively slow in practice due to the way the caching works. -- You 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