Skip to content

Commit

Permalink
feat: Add repeatedly that is reducable foldable
Browse files Browse the repository at this point in the history
  • Loading branch information
zane committed Apr 5, 2023
1 parent 81e8872 commit ba51491
Showing 1 changed file with 99 additions and 0 deletions.
99 changes: 99 additions & 0 deletions src/gen/reducers.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
(ns gen.reducers
(:refer-clojure :exclude [repeatedly])
(:require [clojure.core :as clojure]
[clojure.core.reducers :as reducers]))

(declare fold-repeatedly)

(deftype Repeatedly [inv f]
clojure.core.reducers/CollFold
(coll-fold [_ n combinef reducef]
(fold-repeatedly inv f n combinef reducef))

clojure.lang.IReduce
(reduce [_ rf]
(if (pos? inv)
(.reduce (Repeatedly. (dec inv) f)
rf
(f))
(rf)))
(reduce [_ rf x]
(loop [ret x
inv inv]
(if (pos? inv)
(let [ret (rf ret (f))]
(if (reduced? ret)
@ret
(recur ret (dec inv))))
ret))))

(defn repeatedly
"Like `clojure.core/repeatedly`, but is reducible and foldable."
[n f]
(Repeatedly. n f))

(def fjfork @#'reducers/fjfork)
(def fjjoin @#'reducers/fjjoin)
(def fjtask @#'reducers/fjtask)
(def fjinvoke @#'reducers/fjinvoke)

(defn- fold-repeatedly
[inv f n combinef reducef]
(cond (< inv 1) (combinef)

(<= inv n)
(reduce reducef (combinef) (Repeatedly. inv f))

:else
(let [inv1 (quot inv 2)
inv2 (+ inv1 (mod inv 2))
fc (fn [inv]
#(fold-repeatedly inv f n combinef reducef))]
(fjinvoke
#(let [f1 (fc inv1)
t2 (fjtask (fc inv2))]
(fjfork t2)
(combinef (f1) (fjjoin t2)))))))

(comment

(time (into [] (clojure/repeatedly 1000000 rand)))
(time (into [] (repeatedly 1000000 rand)))

(time (reduce + (clojure/repeatedly 1000000 rand)))
(time (reduce + (repeatedly 1000000 rand)))

(time (reducers/fold + (clojure/repeatedly 1000000 rand)))
(time (reducers/fold + (repeatedly 1000000 rand)))

(time (reducers/fold 10 + + (clojure/repeatedly 1000000 rand)))
(time (reducers/fold 10 + + (repeatedly 1000000 rand)))

(time (reducers/fold 2 + + (clojure/repeatedly 1000000 rand)))
(time (reducers/fold 2 + + (repeatedly 1000000 rand)))

(time (reducers/fold 1 + + (clojure/repeatedly 1000000 rand)))
(time (reducers/fold 1 + + (repeatedly 1000000 rand)))

;;

(def slow-rand #(do (Thread/sleep 0 1) (rand)))

(time (reduce + (clojure/repeatedly 1000 slow-rand)))
(time (reduce + (repeatedly 1000 slow-rand)))

(time (reducers/fold + (clojure/repeatedly 1000 slow-rand)))
(time (reducers/fold + (repeatedly 1000 slow-rand)))

(time (reducers/fold 10 + + (clojure/repeatedly 1000 slow-rand)))
(time (reducers/fold 10 + + (repeatedly 1000 slow-rand)))

(time (reducers/fold 2 + + (clojure/repeatedly 1000 slow-rand)))
(time (reducers/fold 2 + + (repeatedly 1000 slow-rand)))

(time (reducers/fold 1 + + (clojure/repeatedly 1000 slow-rand)))
(time (reducers/fold 1 + + (repeatedly 1000 slow-rand)))

(set! *print-length* 10)

,)

0 comments on commit ba51491

Please sign in to comment.