(update-in) and getting the new value at the leaf efficiently

2012-04-26 Thread blais
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

2012-04-26 Thread Andy Fingerhut
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

2012-04-26 Thread Jay Fields
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

2012-04-26 Thread blais
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

2012-04-26 Thread David Nolen
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

2012-04-26 Thread blais
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

2012-04-26 Thread David Nolen
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

2012-04-26 Thread blais
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

2012-04-26 Thread David Nolen
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

2012-04-26 Thread kurtharriger
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