Instantly share code, notes, and snippets.

Embed
What would you like to do?
doseq that doesn't blow up with too much bytecode, and w/o (fn []) thunks
(defmacro doseqs
[seq-exprs & body]
(let [stk (gensym "stack__")
level (gensym "level__")
seq-exprs (partition 2 seq-exprs)
bindings (vec (map first seq-exprs))
init-exprs (vec (map second seq-exprs))
nbinds (count init-exprs)
symbol-binds (fn [n]
[(bindings n) `(nth ~stk ~(inc (* n 2)))])
emit-init (fn [n]
`(let [~@(mapcat symbol-binds (range n))]
~(init-exprs n)))]
;; going to create a stack of:
;; [seq0 bind0, seq1 bind1, seq2 bind2]
`(loop [~level 0 ~stk []]
(if (< ~level ~nbinds)
;; incomplete bindings
(let [sidx# (* 2 ~level)
previously-bound?# (< sidx# (count ~stk))
seq# (if-let [s# (and previously-bound?# (get ~stk sidx#))]
(next s#)
(seq (case ~level
~@(interleave (range nbinds)
(map emit-init (range nbinds))))))]
(if seq#
(let [~stk (if previously-bound?#
(pop (pop ~stk))
~stk)]
(recur (inc ~level)
(conj ~stk seq# (first seq#))))
(when (pos? ~level)
(recur (dec ~level) (pop (pop ~stk))))))
(let [~@(mapcat symbol-binds (range nbinds))]
~@body
(recur (dec ~level) ~stk))))))
(doseqs [x (range 5)
y (range 4)
z (range 3)
a (range 2)
b (range 3)
c (range 2)
d (range 2)
e (range 2)]
(println [x y z a b c d e]))
;; macroexpand
(loop [level__12802 0 stack__12801 []]
(if (< level__12802 8)
(let [sidx__10435__auto__ (* 2 level__12802)
previously-bound?__10436__auto__ (<
sidx__10435__auto__
(count stack__12801))
seq__10437__auto__ (if-let [s__10438__auto__
(and
previously-bound?__10436__auto__
(get
stack__12801
sidx__10435__auto__))]
(next s__10438__auto__)
(seq
(case
level__12802
0
(let [] (range 5))
1
(let
[x (nth stack__12801 1)]
(range 4))
2
(let
[x (nth stack__12801 1)
y (nth stack__12801 3)]
(range 3))
3
(let
[x (nth stack__12801 1)
y (nth stack__12801 3)
z (nth stack__12801 5)]
(range 2))
4
(let
[x (nth stack__12801 1)
y (nth stack__12801 3)
z (nth stack__12801 5)
a (nth stack__12801 7)]
(range 3))
5
(let
[x (nth stack__12801 1)
y (nth stack__12801 3)
z (nth stack__12801 5)
a (nth stack__12801 7)
b (nth stack__12801 9)]
(range 2))
6
(let
[x (nth stack__12801 1)
y (nth stack__12801 3)
z (nth stack__12801 5)
a (nth stack__12801 7)
b (nth stack__12801 9)
c (nth stack__12801 11)]
(range 2))
7
(let
[x (nth stack__12801 1)
y (nth stack__12801 3)
z (nth stack__12801 5)
a (nth stack__12801 7)
b (nth stack__12801 9)
c (nth stack__12801 11)
d (nth stack__12801 13)]
(range 2)))))]
(if seq__10437__auto__
(let [stack__12801 (if previously-bound?__10436__auto__
(pop (pop stack__12801))
stack__12801)]
(recur
(inc level__12802)
(conj
stack__12801
seq__10437__auto__
(first seq__10437__auto__))))
(when (pos? level__12802)
(recur (dec level__12802) (pop (pop stack__12801))))))
(let [x (nth stack__12801 1)
y (nth stack__12801 3)
z (nth stack__12801 5)
a (nth stack__12801 7)
b (nth stack__12801 9)
c (nth stack__12801 11)
d (nth stack__12801 13)
e (nth stack__12801 15)]
(println [x y z a b c d e])
(recur (dec level__12802) stack__12801))))
@ghadishayban

This comment has been minimized.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment