To clarify slightly, the Java Language Specification section 5.1.7 requires that the implementation cache *boxed* ints from -128 to 127, boolean true/false, and characters from \u0000 and \u007f. Because Clojure defaults to boxing in many cases you'll see the same effect.
The persistent collections do go through factories and already cache one special case: empty list/vector/set/map. This is also where the choice is made as to the type of persistent map (array or hash impl) based on size (https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/RT.java#L1457). I think in general, there is not enough commonality across programs for the cost of the check to be more costly than the benefits to be saved in memory so this is not something Clojure would ever do generically. But, if this is tradeoff is important to you, then creating your own factory function for collections and memoizing it would be a good way to achieve that. On Sunday, May 4, 2014 10:21:28 PM UTC-5, Leif wrote: > > > The general technique in lisp is called hash consing (a.k.a. flyweight > pattern, a.k.a. interning). Java strings, clojure symbols, and keywords > are interned. And small integers, apparently. > > The basic idea is to create memoized versions of all the data constructors > and only use them. This is basically what you did in your example and what > Gary suggested. So, if you truly wanted something general, you'd probably > have to reimplement a lot of clojure.core, or restrict yourself to a small > number of constructor fns. > > If the vectors in your example are the only composite structure that needs > sharing, and they represent points, say: > > (def mk-point (memoize (fn [x y] [x y]))) ; obviously lots of options here > (caching strategy, weak refs) > > (def m1 {:a (mk-point 1 2)}) > > (def m2 (assoc m1 :b (mk-point 1 2))) > > (identical? (m2 :a) (m2 :b)) ; => true > > If the maps themselves need to be shared, you'll have to make your own > version of assoc, dissoc, maybe conj & into, etc etc, and remember to > always use them. It could get complicated. > > --Leif > > On Saturday, May 3, 2014 10:27:29 PM UTC-4, Mike Fikes wrote: >> >> Are there common techniques or idioms for achieving structural sharing >> when composing data where equivalences exist? >> >> (My motivation is to reduce heap usage for a particular problem I'm >> working on that involves a lot of repeated data.) >> >> As a specific example, consider sharing equivalent map values: >> >> (def m1 {:a [1 2]}) >> >> (def m2 (assoc m1 :b [1 2])) >> >> >> (identical? (m2 :a) (m2 :b)) >> >> ;; => false >> >> >> For this simple example, I can force sharing by introducing a variant of >> assoc which looks at existing values: >> >> >> (defn assoc-id [map key val] (assoc map key (get (apply hash-set (vals >> map)) val val))) >> >> >> And using it results in a map with two identical values: >> >> >> (def m3 (assoc-id m1 :b [1 2])) >> >> >> (identical? (m3 :a) (m3 :b)) >> >> ;; => true >> >> >> But, of course, this approach could get to be expensive and/or unwieldy >> if not done carefully. >> >> >> So, I was wondering if there are general techniques in this area. I'm >> sure I'm not the first to come across it. We already get this >> automatically for boxing of small integers: >> >> >> (identical? 5 5) >> >> ;; => true >> >> >> (identical? 500 500) >> >> ;; => false >> >> >> So I suppose I'm essentially looking for the same idea but for larger >> non-primitive "values". >> >> >> >> -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.