Skip to content

Commit ba51491

Browse files
committed
feat: Add repeatedly that is reducable foldable
1 parent 81e8872 commit ba51491

File tree

1 file changed

+99
-0
lines changed

1 file changed

+99
-0
lines changed

src/gen/reducers.clj

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
(ns gen.reducers
2+
(:refer-clojure :exclude [repeatedly])
3+
(:require [clojure.core :as clojure]
4+
[clojure.core.reducers :as reducers]))
5+
6+
(declare fold-repeatedly)
7+
8+
(deftype Repeatedly [inv f]
9+
clojure.core.reducers/CollFold
10+
(coll-fold [_ n combinef reducef]
11+
(fold-repeatedly inv f n combinef reducef))
12+
13+
clojure.lang.IReduce
14+
(reduce [_ rf]
15+
(if (pos? inv)
16+
(.reduce (Repeatedly. (dec inv) f)
17+
rf
18+
(f))
19+
(rf)))
20+
(reduce [_ rf x]
21+
(loop [ret x
22+
inv inv]
23+
(if (pos? inv)
24+
(let [ret (rf ret (f))]
25+
(if (reduced? ret)
26+
@ret
27+
(recur ret (dec inv))))
28+
ret))))
29+
30+
(defn repeatedly
31+
"Like `clojure.core/repeatedly`, but is reducible and foldable."
32+
[n f]
33+
(Repeatedly. n f))
34+
35+
(def fjfork @#'reducers/fjfork)
36+
(def fjjoin @#'reducers/fjjoin)
37+
(def fjtask @#'reducers/fjtask)
38+
(def fjinvoke @#'reducers/fjinvoke)
39+
40+
(defn- fold-repeatedly
41+
[inv f n combinef reducef]
42+
(cond (< inv 1) (combinef)
43+
44+
(<= inv n)
45+
(reduce reducef (combinef) (Repeatedly. inv f))
46+
47+
:else
48+
(let [inv1 (quot inv 2)
49+
inv2 (+ inv1 (mod inv 2))
50+
fc (fn [inv]
51+
#(fold-repeatedly inv f n combinef reducef))]
52+
(fjinvoke
53+
#(let [f1 (fc inv1)
54+
t2 (fjtask (fc inv2))]
55+
(fjfork t2)
56+
(combinef (f1) (fjjoin t2)))))))
57+
58+
(comment
59+
60+
(time (into [] (clojure/repeatedly 1000000 rand)))
61+
(time (into [] (repeatedly 1000000 rand)))
62+
63+
(time (reduce + (clojure/repeatedly 1000000 rand)))
64+
(time (reduce + (repeatedly 1000000 rand)))
65+
66+
(time (reducers/fold + (clojure/repeatedly 1000000 rand)))
67+
(time (reducers/fold + (repeatedly 1000000 rand)))
68+
69+
(time (reducers/fold 10 + + (clojure/repeatedly 1000000 rand)))
70+
(time (reducers/fold 10 + + (repeatedly 1000000 rand)))
71+
72+
(time (reducers/fold 2 + + (clojure/repeatedly 1000000 rand)))
73+
(time (reducers/fold 2 + + (repeatedly 1000000 rand)))
74+
75+
(time (reducers/fold 1 + + (clojure/repeatedly 1000000 rand)))
76+
(time (reducers/fold 1 + + (repeatedly 1000000 rand)))
77+
78+
;;
79+
80+
(def slow-rand #(do (Thread/sleep 0 1) (rand)))
81+
82+
(time (reduce + (clojure/repeatedly 1000 slow-rand)))
83+
(time (reduce + (repeatedly 1000 slow-rand)))
84+
85+
(time (reducers/fold + (clojure/repeatedly 1000 slow-rand)))
86+
(time (reducers/fold + (repeatedly 1000 slow-rand)))
87+
88+
(time (reducers/fold 10 + + (clojure/repeatedly 1000 slow-rand)))
89+
(time (reducers/fold 10 + + (repeatedly 1000 slow-rand)))
90+
91+
(time (reducers/fold 2 + + (clojure/repeatedly 1000 slow-rand)))
92+
(time (reducers/fold 2 + + (repeatedly 1000 slow-rand)))
93+
94+
(time (reducers/fold 1 + + (clojure/repeatedly 1000 slow-rand)))
95+
(time (reducers/fold 1 + + (repeatedly 1000 slow-rand)))
96+
97+
(set! *print-length* 10)
98+
99+
,)

0 commit comments

Comments
 (0)