macro | since v0.0-927 | clojure.core/for | Edit |
(for seq-exprs body-expr)
List comprehension.
Takes a vector of one or more binding-form/collection-expr pairs, each followed by zero or more modifiers, and yields a lazy sequence of evaluations of expr.
Collections are iterated in a nested fashion, rightmost fastest, and nested
coll-exprs can refer to bindings created in prior binding-forms. Supported
modifiers are: :let [binding-form expr ...]
, :while test
, :when test
.
List comprehension. Takes a vector of one or more binding-form/collection-expr pairs, each followed by zero or more modifiers, and yields a lazy sequence of evaluations of expr. Collections are iterated in a nested fashion, rightmost fastest, and nested coll-exprs can refer to bindings created in prior binding-forms. Supported modifiers are: :let [binding-form expr ...], :while test, :when test. (take 100 (for [x (range 100000000) y (range 1000000) :while (< y x)] [x y]))
(core/defmacro for
[seq-exprs body-expr]
(assert-args for
(vector? seq-exprs) "a vector for its binding"
(even? (count seq-exprs)) "an even number of forms in binding vector")
(core/let [to-groups (core/fn [seq-exprs]
(reduce (core/fn [groups [k v]]
(if (core/keyword? k)
(conj (pop groups) (conj (peek groups) [k v]))
(conj groups [k v])))
[] (partition 2 seq-exprs)))
err (core/fn [& msg] (throw (ex-info (apply core/str msg) {})))
emit-bind (core/fn emit-bind [[[bind expr & mod-pairs]
& [[_ next-expr] :as next-groups]]]
(core/let [giter (gensym "iter__")
gxs (gensym "s__")
do-mod (core/fn do-mod [[[k v :as pair] & etc]]
(core/cond
(= k :let) `(let ~v ~(do-mod etc))
(= k :while) `(when ~v ~(do-mod etc))
(= k :when) `(if ~v
~(do-mod etc)
(recur (rest ~gxs)))
(core/keyword? k) (err "Invalid 'for' keyword " k)
next-groups
`(let [iterys# ~(emit-bind next-groups)
fs# (seq (iterys# ~next-expr))]
(if fs#
(concat fs# (~giter (rest ~gxs)))
(recur (rest ~gxs))))
:else `(cons ~body-expr
(~giter (rest ~gxs)))))]
(if next-groups
#_ "not the inner-most loop"
`(fn ~giter [~gxs]
(lazy-seq
(loop [~gxs ~gxs]
(when-first [~bind ~gxs]
~(do-mod mod-pairs)))))
#_"inner-most loop"
(core/let [gi (gensym "i__")
gb (gensym "b__")
do-cmod (core/fn do-cmod [[[k v :as pair] & etc]]
(core/cond
(= k :let) `(let ~v ~(do-cmod etc))
(= k :while) `(when ~v ~(do-cmod etc))
(= k :when) `(if ~v
~(do-cmod etc)
(recur
(unchecked-inc ~gi)))
(core/keyword? k)
(err "Invalid 'for' keyword " k)
:else
`(do (chunk-append ~gb ~body-expr)
(recur (unchecked-inc ~gi)))))]
`(fn ~giter [~gxs]
(lazy-seq
(loop [~gxs ~gxs]
(when-let [~gxs (seq ~gxs)]
(if (chunked-seq? ~gxs)
(let [c# ^not-native (chunk-first ~gxs)
size# (count c#)
~gb (chunk-buffer size#)]
(if (coercive-boolean
(loop [~gi 0]
(if (< ~gi size#)
(let [~bind (-nth c# ~gi)]
~(do-cmod mod-pairs))
true)))
(chunk-cons
(chunk ~gb)
(~giter (chunk-rest ~gxs)))
(chunk-cons (chunk ~gb) nil)))
(let [~bind (first ~gxs)]
~(do-mod mod-pairs)))))))))))]
`(let [iter# ~(emit-bind (to-groups seq-exprs))]
(iter# ~(second seq-exprs)))))