Created
September 23, 2018 23:44
-
-
Save taylorwood/47cfb3ec0cfb92dfc25b834f5db0320f to your computer and use it in GitHub Desktop.
Clojure transducers
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(defn zip | |
"Returns a transducer that zips cs with inputs." | |
[& cs] | |
(fn [rf] | |
(let [cs (volatile! cs)] | |
(fn | |
([] (rf)) | |
([result] (rf result)) | |
([result item] | |
(if (every? seq @cs) | |
(let [firsts (map first @cs)] | |
(do (vswap! cs #(map rest %)) | |
(rf result (cons item firsts)))) | |
result)))))) | |
(comment | |
(sequence | |
(zip '[a b c] '[x y z]) | |
(range 10)) | |
=> ((0 a x) (1 b y) (2 c z))) | |
(defn zip-with | |
"Like zip but applies input with cs values to f." | |
[f & cs] | |
(fn [rf] | |
(let [cs (volatile! cs)] | |
(fn | |
([] (rf)) | |
([result] (rf result)) | |
([result item] | |
(if (every? seq @cs) | |
(let [firsts (map first @cs)] | |
(do (vswap! cs #(map rest %)) | |
(rf result (apply f item firsts)))) | |
result)))))) | |
(comment | |
(sequence | |
(zip-with str '[a b c] '[x y z]) | |
(range 10)) | |
=> ("0ax" "1by" "2cz")) | |
(defn itermap | |
"Takes a function with 1-arity for first input and 2-arity for each | |
additional input, where the first argument is the result of the previous | |
invocation. Returns a map-like transducer with iterate-like behavior." | |
[f] | |
(fn [rf] | |
(let [prev (volatile! ::void)] | |
(fn | |
([] (rf)) | |
([result] (rf result)) | |
([result input] | |
(let [p @prev | |
value (if (= ::void p) | |
(f input) | |
(f p input))] | |
(vreset! prev value) | |
(rf result value))) | |
([result input & inputs] | |
(let [p @prev | |
value (if (= ::void p) | |
(apply f input inputs) | |
(apply f p input inputs))] | |
(vreset! prev value) | |
(rf result value))))))) | |
(comment | |
(sequence (itermap +) (range 10)) | |
=> (0 1 3 6 10 15 21 28 36 45) | |
(sequence (itermap str) (range 5)) | |
=> ("0" "01" "012" "0123" "01234") | |
(def vowels #{\a \e \i \o \u \y}) | |
(def alphabet (into #{} (map char) (range 97 123))) | |
(sequence | |
(comp | |
(itermap (fn | |
([v a] a) | |
([prev v a] | |
(if (and (vowels prev) | |
(< 3/4 (rand))) | |
a | |
v)))) | |
(partition-all 5) | |
(map #(apply str %)) | |
(take 5)) | |
(repeatedly #(rand-nth (seq vowels))) | |
(repeatedly #(rand-nth (seq alphabet)))) | |
=> ("unagi" "oyuuu" "aouae" "yoaiu" "ouuwe")) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment