Skip to content

Instantly share code, notes, and snippets.

@richhickey
Last active February 28, 2024 18:29
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save richhickey/dc17e6c5cb7e4938e59d5b2e6cc833cb to your computer and use it in GitHub Desktop.
Save richhickey/dc17e6c5cb7e4938e59d5b2e6cc833cb to your computer and use it in GitHub Desktop.
(defn iteration
"creates a seqable/reducible given step!,
a function of some (opaque continuation data) k
step! - fn of k/nil to (opaque) 'ret'
:some? - fn of ret -> truthy, indicating there is a value
will not call vf/kf nor continue when false
:vf - fn of ret -> v, the values produced by the iteration
:kf - fn of ret -> next-k or nil (will not continue)
:initk - the first value passed to step!
vf, kf default to identity, some? defaults to some?, initk defaults to nil
it is presumed that step! with non-initk is unreproducible/non-idempotent
if step! with initk is unreproducible it is on the consumer to not consume twice"
[step! & {:keys [vf kf some? initk]
:or {vf identity
kf identity
some? some?
initk nil}}]
(reify
clojure.lang.Seqable
(seq [_]
((fn next [ret]
(when (some? ret)
(cons (vf ret)
(when-let [k (kf ret)]
(lazy-seq (next (step! k)))))))
(step! initk)))
clojure.lang.IReduceInit
(reduce [_ rf init]
(loop [acc init
ret (step! initk)]
(if (some? ret)
(let [acc (rf acc (vf ret))]
(if (reduced? acc)
@acc
(if-let [k (kf ret)]
(recur acc (step! k))
acc)))
acc)))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment