2014-01-10 38 views
1

我學習的Clojure和在這個過程中遇到了這個例子來自O'Reilly出版的書「的Clojure編程」:爲什麼`persistent!`只能得到瞬態的前8個項目?

(let [tm (transient {})] 
    (doseq [x (range 100)] 
    (assoc! tm x 0)) 
    (persistent! tm)) 

它給出結果{0 0, 1 0, 2 0, 3 0, 4 0, 5 0, 6 0, 7 0}

另外:

(let [tm (transient {})] 
    (assoc! tm 0 0) 
    (assoc! tm 1 0) 
    (assoc! tm 2 0) 
    (assoc! tm 3 0) 
    (assoc! tm 4 0) 
    (assoc! tm 5 0) 
    (assoc! tm 6 0) 
    (assoc! tm 7 0) 
    (assoc! tm 8 0) 
    (persistent! tm) 
) 

給出了相同的結果:{0 0, 1 0, 2 0, 3 0, 4 0, 5 0, 6 0, 7 0}

爲什麼只有前8個項目才能進入持久性收集?

+0

可能的重複[在Clojure 1.3中使用瞬態時存在什麼問題?](http://stackoverflow.com/questions/8971675/what-gotchas-exist-when-working-with-transient-in-clojure- 1-3) – amalloy

+0

我不認爲這是一個重複的問題,儘管兩者的答案都是一樣的。 – Ben

回答

10

爲什麼只有前8項?

(type {}) 
;=> clojure.lang.PersistentArrayMap 
(type {0 0, 1 0, 2 0, 3 0, 4 0, 5 0, 6, 0}) 
;=> clojure.lang.PersistentArrayMap 
(type {0 0, 1 0, 2 0, 3 0, 4 0, 5 0, 6, 0, 7 0}) 
;=> clojure.lang.PersistentArrayMap 
(type {0 0, 1 0, 2 0, 3 0, 4 0, 5 0, 6, 0, 7 0, 8 0}) 
;=> clojure.lang.PersistentHashMap 

因爲地圖的表示在8對和8對以下的對之間變化。既然你對原創「抨擊」,你從來沒有捕捉到表達的變化。

在處理瞬變時,您必須始終捕獲並使用返回值。

+0

Shepmaster評論如下有一些非常具有解釋性的鏈接:http://stackoverflow.com/questions/21056214/why-does-persistent-only-get-the-first-eight-items-from-a-transient#comment31662350_21056424 另外,本在評論中提出了正確的陳述。 – christopherbalz

1

多麼迷人!

起初,這看起來像一個問題與懶惰seqs的分塊 - 要測試,我稍微修改您的示例:

(let [tm (transient {})] 
    (doseq [x (range 100)] 
    (println "assoc! " x) 
    (assoc! tm x 0)) 
    (persistent! tm)) 

令我驚訝的是,這確實打印100行文字 - 但結果集合只包含8個項目,正如你所觀察的那樣。我不能說爲什麼,確切地說,除了它似乎是實施瞬變的人爲因素之外。

什麼我可以說的是,這不是慣用clojure。對於建設作爲指定地圖的任務,這裏是我會怎麼做:

(reduce (fn [m n] (assoc m n 0)) {} (range 100)) 

如果這實際上是一個問題的表現明智的,我可能會考慮一個loop結構的內部瞬變:

(loop [m (transient {}) 
     ns (range 100)] 
    (if-let [n (first ns)] 
    (recur (assoc! m n 0) (rest ns)) 
    (persistent! m)) 

您面臨的關鍵問題是,儘管瞬變是可變的,但它們旨在以有些功能的方式使用。如果您將瞬態映射視爲一個持久映射 - 也就是說,保留assoc!的結果而不是假設一個引用總是有效的 - 那麼您會沒事的。

+2

關鍵部分來自[assoc!'的示例](http://clojuredocs.org/clojure_core/clojure.core/assoc!):「瞬態不意味着被阻擋在原地」。還有更多關於這種情況的描述。簡短的版本是數據表示可能會在某些點發生變化。 – Shepmaster

相關問題