Make x/for to unroll some reductions
When an expression in collection position in `x/for` is a collection literal with less than 4 items (or tagged with `^:unroll`) then the collection is not allocated and the reduction over it is unrolled.
This commit is contained in:
parent
23feac44dc
commit
8f04ad0748
3 changed files with 70 additions and 40 deletions
12
README.md
12
README.md
|
|
@ -21,7 +21,7 @@ Transducing contexts: `transjuxt` (for performing several transductions in a sin
|
|||
Add this dependency to your project:
|
||||
|
||||
```clj
|
||||
[net.cgrand/xforms "0.9.4"]
|
||||
[net.cgrand /xforms "0.9.5"]
|
||||
```
|
||||
|
||||
```clj
|
||||
|
|
@ -209,6 +209,16 @@ Evaluation count : 24 in 6 samples of 4 calls.
|
|||
|
||||
## Changelog
|
||||
|
||||
### 0.9.5
|
||||
|
||||
* Short (up to 4) literal collections (or literal collections with `:unroll` metadata) in collection positions in `x/for` are unrolled.
|
||||
This means that the collection is not allocated.
|
||||
If it's a collection of pairs (e.g. maps), pairs themselves won't be allocated.
|
||||
|
||||
### 0.9.4
|
||||
|
||||
* Add `x/into-by-key` short hand
|
||||
|
||||
### 0.7.2
|
||||
|
||||
* Fix transients perf issue in Clojurescript
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
(defproject net.cgrand/xforms "0.9.4"
|
||||
(defproject net.cgrand/xforms "0.9.5"
|
||||
:description "Extra transducers for Clojure"
|
||||
:url "https://github.com/cgrand/xforms"
|
||||
:license {:name "Eclipse Public License"
|
||||
|
|
|
|||
|
|
@ -15,6 +15,16 @@
|
|||
(defn- no-user-meta? [x]
|
||||
(= {} (dissoc (or (meta x) {}) :file :line :column :end-line :end-column)))
|
||||
|
||||
(defmacro unreduced->
|
||||
"Thread first while threaded value is not reduced.
|
||||
Doesn't unreduce the final value."
|
||||
([x] x)
|
||||
([x expr & exprs]
|
||||
`(let [x# ~x]
|
||||
(if (reduced? x#)
|
||||
x#
|
||||
(unreduced-> (-> x# ~expr) ~@exprs)))))
|
||||
|
||||
(defmacro for
|
||||
"Like clojure.core/for with the first expression being replaced by % (or _). Returns a transducer.
|
||||
When the first expression is not % (or _) returns an eduction."
|
||||
|
|
@ -33,12 +43,22 @@
|
|||
:let `(let ~expr ~body)
|
||||
:when `(if ~expr ~body ~acc)
|
||||
:while `(if ~expr ~body (reduced ~acc))
|
||||
(if (and (coll? expr) (not (seq? expr))
|
||||
(or (<= (core/count expr) 4) (:unroll (meta expr))))
|
||||
(let [body-rf (gensym 'body-rf)]
|
||||
(if (and (destructuring-pair? binding) (every? vector? expr))
|
||||
`(let [~body-rf (fn [~acc ~@binding] ~body)]
|
||||
(unreduced (unreduced-> ~acc
|
||||
~@(map (fn [[k v]] `(~body-rf ~k ~v)) expr))))
|
||||
`(let [~body-rf (fn [~acc ~binding] ~body)]
|
||||
(unreduced (unreduced-> ~acc
|
||||
~@(map (fn [v] `(~body-rf ~v)) expr))))))
|
||||
(if (destructuring-pair? binding)
|
||||
`(let [expr# ~expr]
|
||||
(if (and (map? expr#) (kvreducible? expr#))
|
||||
(core/reduce-kv (fn [~acc ~@binding] ~body) ~acc expr#)
|
||||
(core/reduce (fn [~acc ~binding] ~body) ~acc expr#)))
|
||||
`(core/reduce (fn [~acc ~binding] ~body) ~acc ~expr))))
|
||||
`(core/reduce (fn [~acc ~binding] ~body) ~acc ~expr)))))
|
||||
init rpairs))
|
||||
nested-reduceds (core/for [[expr binding] rpairs
|
||||
:when (not (keyword? binding))]
|
||||
|
|
|
|||
Loading…
Reference in a new issue