Skip to content

Instantly share code, notes, and snippets.

@cgrand
Created July 14, 2021 14:58
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save cgrand/4ff84470c5849ba74bea6e4461e013c0 to your computer and use it in GitHub Desktop.
Save cgrand/4ff84470c5849ba74bea6e4461e013c0 to your computer and use it in GitHub Desktop.
ClojureDart's for macro
;; For ClojureDart in a bout of NIH syndrome we rewrote Clojure for
;; it seems to be faster because we don't use concat
(defmacro for
"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]))"
[seq-exprs body-expr]
(letfn
[(emit [seq-exprs ors]
(let [[binding expr & seq-exprs] seq-exprs
iter (gensym 'iter__)
arg (gensym 'coll__)
wrap
(fn wrap [mods body]
(if-some [[mod expr & more-mods] (seq mods)]
(let [body (wrap more-mods body)]
(case mod
:let `(let ~expr ~body)
:while `(if ~expr ~body (or ~@ors))
:when `(if ~expr ~body (recur (next ~arg)))))
body))
ors (cons `(~iter (next ~arg)) ors)
nmods (* 2 (count (take-while keyword? (take-nth 2 seq-exprs))))
mods (take nmods seq-exprs)
seq-exprs (seq (drop nmods seq-exprs))
body
`(let [~binding (first ~arg)]
~(wrap mods
(if seq-exprs
`(or ~(emit seq-exprs ors)
(recur (next ~arg)))
`(cons ~body-expr
(lazy-seq (or ~@ors))))))
body
(if seq-exprs
body
; innermost, also check for chunked
`(if (chunked-seq? ~arg)
~(emit-innermost-chunked arg ors binding
mods body-expr)
~body))]
`((fn ~iter [~arg] (when ~arg ~body))
(seq ~expr))))
(emit-innermost-chunked [arg ors binding mods body-expr]
(let [buf `buf#]
`(let [c# (chunk-first ~arg)
size# (int (count c#))
~buf (chunk-buffer size#)
exit#
(loop [i# (int 0)]
(when (< i# size#)
(or
(let [~binding (-nth c# i#)]
~(chunked-wrap mods
`(chunk-append ~buf ~body-expr)))
(recur (unchecked-inc i#)))))]
(cond
(pos? (count ~buf))
(chunk-cons
(chunk ~buf)
(lazy-seq
(or (when-not exit#
(~(ffirst ors) (chunk-next ~arg)))
~@(next ors))))
exit# (or ~@(next ors))
:else (recur (chunk-next ~arg))))))
(chunked-wrap [mods body]
(if-some [[mod expr & more-mods] (seq mods)]
(let [body (chunked-wrap more-mods body)]
(case mod
:let `(let ~expr ~body)
:while `(if ~expr ~body true)
:when `(when ~expr ~body)))
body))]
`(lazy-seq ~(emit seq-exprs nil))))
@piotr-yuxuan
Copy link

A jaw-dropping ~70-line macro 🤯

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