Is this the correct use of transients?

In Tyler Jennings' Bootstrapping Clojure at Groupon, from 25:14 to 28:24, he discusses two implementations of the function separate, both using transients:

(defn separate-fast-recur [pred coll]
  (loop [true-elements (transient [])
         false-elements (transient [])
         my-coll coll]
    (if (not (empty? my-coll))
      (let [curr (first my-coll)
            tail (rest my-coll)]
        (if (pred curr)
          (recur (conj! true-elements curr) false-elements tail)
          (recur true-elements (conj! false-elements curr) tail)))
      [(persistent! true-elements) (persistent! false-elements)])))

(defn separate-fast-doseq [pred coll]
  (let [true-elements (transient [])
        false-elements (transient [])]
    (doseq [curr coll]
      (if (pred curr)
        (conj! true-elements curr)
        (conj! false-elements curr)))
      [(persistent! true-elements) (persistent! false-elements)]))

(They are both copied verbatim, including the uniomatic indentation in the last line of the second).

He notes that in the benchmark he used, the first function above took 1.1 seconds and the second function above 0.8 seconds, noting that the second, therefore, is superior to the first. However, according to Clojure's transient documentation :

, , . .

, , separate-fast-doseq . , , .

separate-fast-doseq ? ? ( , ?)

+4
1

, . , , conj! . , , conj!, , , .

. Clojure, , conj! . return this . , , . , , .

, , :

(let [m (transient {})]
  (doseq [i (range 20)]
    (assoc! m i i))
  (count (persistent! m)))

8
+7

Source: https://habr.com/ru/post/1681496/


All Articles