Skip to content

Instantly share code, notes, and snippets.

@miner
Created March 19, 2018 20:47
Show Gist options
  • Save miner/d4512cc1f777d46fdc2cb16fdc6f0607 to your computer and use it in GitHub Desktop.
Save miner/d4512cc1f777d46fdc2cb16fdc6f0607 to your computer and use it in GitHub Desktop.
a stateful transducer inspired by @apropos_cast episode #3
(defn digits [n]
{:pre [(int? n) (>= n 0)]}
(loop [digs () remainder n]
(if (< remainder 10)
(conj digs remainder)
(recur (conj digs (rem remainder 10)) (quot remainder 10)))))
(defn digits+rev [n]
(let [ds (digits n)]
(concat ds (reverse ds))))
;; based on preserving-reduced from clojure/core.clj
;; the extra level of `reduced` preserves the early termination value
(defn rf-reduce [rf result xs]
(let [rrf (fn [r x] (let [ret (rf r x)] (if (reduced? ret) (reduced ret) ret)))]
(reduce rrf result xs)))
;; They asked for a stateful transducer solution...
(defn revcat
"Returns a lazy sequence of items from coll followed by the items in reverse order. When
no collection is provided, returns a stateful transducer that buffers a reversed collection
of inputs. Each input passes through to the output. On reaching the end of input, the
buffered elements are passed in as extra inputs. Inspired by @apropos_cast episode #3."
([]
(fn [rf]
(let [rv (volatile! ())]
(fn
([] (rf))
([result] (rf (unreduced (rf-reduce rf result @rv))))
([result input]
(vswap! rv conj input)
(rf result input))))))
([coll] (concat coll (reverse coll))))
(defn apropos3 [n]
(sequence (revcat) (digits n)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment