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.

Reply via email to