Skip to content

Instantly share code, notes, and snippets.

@amalloy
Created February 1, 2011 08:25
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save amalloy/805583 to your computer and use it in GitHub Desktop.
Save amalloy/805583 to your computer and use it in GitHub Desktop.
(defn unfold
"Next and done? are functions that operate on a seed. next should
return a pair, [value new-seed]; the value half of the pair is
inserted into the resulting list, while the new-seed is used to
continue unfolding. Notably, the value is never passed as an
argument to either next or done?."
[next done? seed]
((fn unfold*
[seed]
(lazy-seq
(when-not (done? seed)
(let [[value new-seed] (next seed)]
(cons value
(unfold* new-seed))))))
seed))
;; alternate implementation, using a simple-laziness macro. better?
(defmacro simple-laziness [bindings & body]
(let [inner-fn 'continue
names (take-nth 2 bindings)
values (take-nth 2 (rest bindings))]
`((fn ~inner-fn
~(vec names)
(lazy-seq
~@body))
~@values)))
(defn unfold2
([next seed]
(unfold next (constantly false) seed))
([next done? seed]
(simple-laziness [seed seed]
(when-not (done? seed)
(let [[value new-seed] (next seed)]
(cons value
(continue new-seed)))))))
(defn fibs []
(unfold (fn [[a b]] [a [b (+ a b)]]) (constantly false) [0 1]))
(defn rand-poll [num coll]
(unfold (fn [[remaining items]]
(let [idx (rand-int (count items))]
[(items idx) ; value
[(dec remaining)
(subvec (assoc items idx (items 0)) ; new seed-vector
1)]])) ; numbers left
(comp zero? first)
[num (vec coll)]))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment