Last active
January 22, 2023 00:20
-
-
Save jclaggett/fa4f59272e7c5062ba49392210a377c6 to your computer and use it in GitHub Desktop.
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
(ns ezducerdemo) | |
;; | |
;; 1st take | |
;; | |
(defn ezducer [constructor] | |
(fn [reducer] | |
(let [steps (fn [a vs] | |
;; Use loop/recur instead of reduce to avoid reduce's | |
;; swallowing the special 'reduced' values. | |
(loop [a a vs vs] | |
(if (or (reduced? a) (empty? vs)) | |
a | |
(if (= (first vs) reduced) | |
(reduced a) | |
(recur (reducer a (first vs)) (rest vs)))))) | |
{:keys [step, result] | |
:or {step (fn [v] [v]) | |
result (fn [] [])}} (constructor)] | |
(fn | |
([] (reducer)) | |
([a v] (steps a (step v))) | |
([a] (reducer (unreduced (steps a (result))))))))) | |
(defn ezfilter [pred] | |
(ezducer | |
(fn [] | |
{:step (fn [v] (if (pred v) [v] []))}))) | |
(def drop-all | |
(ezducer | |
(fn [] | |
{:step (fn [_v] [])}))) | |
(defn eztake [n] | |
(if (< n 1) | |
drop-all | |
(ezducer | |
(fn [] | |
(let [*n* (atom n)] | |
{:step (fn [v] | |
(if (< (swap! *n* dec) 1) | |
[v reduced] | |
[v]))}))))) | |
(defn demo [msg xf] [msg (into [] xf (range 10))]) | |
(prn [(demo "Keep odd numbers" (ezfilter odd?)) | |
(demo "take first 3" (eztake 3)) | |
(demo "Composing previous transducers" (comp (ezfilter odd?) (eztake 3)))]) | |
;; | |
;; 2nd take | |
;; | |
(defn steps [reducer a vs] | |
(if (or (reduced? a) (empty? vs)) | |
a | |
(let [[v & vs] vs] | |
(if (= v reduced) | |
(reduced a) | |
(recur reducer | |
(reducer a v) ;; step | |
vs))))) | |
(defn steps-reducer [reducer f] | |
(fn | |
([] (reducer)) ;; init | |
([a v] (steps reducer a (f v))) ;; step | |
([a] (reducer (unreduced (steps reducer a (f))))))) ;; result | |
(defn ezducer2 | |
([f] ;; stateless | |
(fn [reducer] | |
(steps-reducer reducer f))) | |
([f state] ;; stateful | |
(fn [reducer] | |
(let [*state* (atom state) | |
stateful-f (fn | |
([] (let [[_ vs] (f @*state*)] vs)) | |
([v] (let [[state vs] (f @*state* v)] | |
(reset! *state* state) | |
vs)))] | |
(steps-reducer reducer stateful-f))))) | |
(defn ezfilter2 [pred] | |
(ezducer2 | |
(fn | |
([] []) | |
([v] (if (pred v) [v] []))))) | |
(def drop-all2 | |
(ezducer2 | |
(fn | |
([] []) | |
([_] [])))) | |
(defn eztake2 [n] | |
(if (< n 1) | |
drop-all2 | |
(ezducer2 | |
(fn | |
([n] [n []]) | |
([n v] | |
(let [n (dec n)] | |
[n (if (< n 1) [v reduced] [v])]))) | |
n))) | |
(defn demo [msg xf] [msg (into [] xf (range 10))]) | |
(prn [(demo "[2nd] Keep odd numbers" (ezfilter2 odd?)) | |
(demo "[2nd] take first 3" (eztake2 3)) | |
(demo "[2nd] Composing previous transducers" (comp (ezfilter2 odd?) (eztake2 3)))]) | |
;; | |
;; 3rd take | |
;; | |
(defn ezducer3 [& {:keys [step result state]}] | |
(let [[step result] | |
(if (nil? state) | |
(let [step' (if (nil? step) (fn [v] [v]) step) | |
result' (if (nil? result) (fn [] []) result)] | |
[step' result']) | |
(let [*state* (atom state) | |
step' (if (nil? step) (fn [s v] [s [v]]) step) | |
result' (if (nil? result) (fn [s] [s []]) result) | |
step'' (fn [v] | |
(let [[state vs] (step' @*state* v)] | |
(reset! *state* state) | |
vs)) | |
result'' (fn [] | |
(let [[_state vs] (result' @*state*)] | |
vs))] | |
[step'' result'']))] | |
(fn [reducer] | |
(letfn [(steps [a [v :as vs]] | |
(if (or (reduced? a) (empty? vs)) | |
a | |
(if (= v reduced) | |
(reduced a) | |
(recur (reducer a v) ;; step | |
(rest vs)))))] | |
(fn | |
([] (reducer)) ;; init | |
([a v] (steps a (step v))) | |
([a] (reducer (unreduced (steps a (result)))))))))) ;; result | |
(defn ezfilter3 [pred] | |
(ezducer3 | |
:step (fn [v] (if (pred v) [v] [])))) | |
(def drop-all3 | |
(ezducer3 | |
:step (fn [_] []))) | |
(defn eztake3 [n] | |
(if (< n 1) | |
drop-all3 | |
(ezducer3 | |
:state n | |
:step (fn [n v] | |
(let [n (dec n)] | |
[n (if (< n 1) | |
[v reduced] | |
[v])]))))) | |
(prn [(demo "[3rd] Keep odd numbers" (ezfilter3 odd?)) | |
(demo "[3rd] take first 3" (eztake3 3)) | |
(demo "[3rd] Composing previous transducers" (comp (ezfilter3 odd?) (eztake2 3)))]) | |
;; | |
;; 4th take | |
;; | |
(defn ezducer4 | |
([constructor] | |
(fn [reducer] | |
(let [*a* (atom) | |
step! (fn | |
([] (reduced? (swap! *a* (fn [a] (if (reduced? a) a (reduced a)))))) | |
([v] (reduced? (swap! *a* (fn [a v] (if (reduced? a) a (reducer a v))) v)))) | |
{:keys [step result]} (constructor step!) | |
step (if (nil? step) (fn [v] (step! v)) step) | |
result (if (nil? result) (fn []) result)] | |
(fn | |
([] (reducer)) ;; init | |
([a v] (reset! *a* a) (step v) @*a*) | |
([a] (reset! *a* a) (result) (reducer (unreduced @*a*))))))) ;; result | |
([state constructor] | |
(fn [reducer] | |
(let [*a* (atom) | |
step! (fn | |
([] (reduced? (swap! *a* (fn [a] (if (reduced? a) a (reduced a)))))) | |
([v] (reduced? (swap! *a* (fn [a v] (if (reduced? a) a (reducer a v))) v)))) | |
{:keys [step result]} (constructor step!) | |
step (if (nil? step) (fn [state v] (step! v) state) step) | |
result (if (nil? result) (fn [_]) result) | |
*state* (atom state)] | |
(fn | |
([] (reducer)) ;; init | |
([a v] (reset! *a* a) (swap! *state* step v) @*a*) | |
([a] (reset! *a* a) (swap! *state* result) (reducer (unreduced @*a*)))))))) ;; result | |
(def drop-all4 | |
(ezducer4 | |
(fn [step] | |
{:step (fn [_])}))) | |
(defn eztake4 [n] | |
(if (< n 1) | |
drop-all4 | |
(ezducer4 | |
n ;; state initialized | |
(fn [step] | |
{:step (fn [n v] | |
(step v) | |
(let [n (dec n)] | |
(when (< n 1) | |
(step)) | |
n))})))) | |
(prn [(demo "[4th] Keep odd numbers" (ezfilter4 odd?)) | |
(demo "[4th] take first 3" (eztake4 3)) | |
(demo "[4th] Composing previous transducers" (comp (ezfilter3 odd?) (eztake4 4)))]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment