Skip to content

Commit 953a402

Browse files
committed
Adds async reduce and walk
... and betters some doc strings
1 parent eaa1559 commit 953a402

File tree

1 file changed

+90
-29
lines changed

1 file changed

+90
-29
lines changed

src/jtk_dvlp/async.cljc

+90-29
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
(ns jtk-dvlp.async
22
(:refer-clojure
3-
:exclude [map pmap amap reduce into])
3+
:exclude [map pmap amap areduce reduce into])
44

55
#?(:cljs
66
(:require-macros
@@ -17,7 +17,7 @@
1717

1818
#?(:clj
1919
(:import
20-
[clojure.lang ExceptionInfo]
20+
[clojure.lang ExceptionInfo MapEntry]
2121
[clojure.core.async.impl.channels ManyToManyChannel]))
2222

2323
,,,)
@@ -97,6 +97,37 @@
9797
(ex-info "unknown" {:code :unknown} e#))))
9898
chs))
9999

100+
(defn smap
101+
"Like `clojure.core/map` but given function `<f` is async. Execution of `<f` with values of `xs` will be sequential with the given order of `xs`. Carries thrown exception (will convert to `ExceptionInfo`) as result.
102+
103+
Also see `amap`"
104+
[<f & xs]
105+
(go-loop [result [], xs xs]
106+
(if (ffirst xs)
107+
(let [next-result
108+
(->> xs
109+
(mapv first)
110+
(apply <f)
111+
(<!))]
112+
113+
(recur
114+
(conj result next-result)
115+
(mapv next xs)))
116+
117+
result)))
118+
119+
(def chain
120+
"Alias for `smap`"
121+
smap)
122+
123+
(defn amap
124+
"Like `clojure.core/map` but given function `<f` is async. Execution of `<f` with values of `xs` can be unordered an for clojure (not clojurescript) in parallel. Carries thrown exception (will convert to `ExceptionInfo`) as result.
125+
126+
Also see `smap`"
127+
[<f & xs]
128+
(->> (apply clojure.core/map <f xs)
129+
(map vector)))
130+
100131
(defn reduce
101132
"Like `core.async/reduce` but carries thrown exception (will convert to `ExceptionInfo`) as result."
102133
[f init ch]
@@ -112,37 +143,67 @@
112143
(reduced (ex-info "unknown" {:code :unknown} e#)))))
113144
init ch))
114145

146+
(defn areduce
147+
"Like `clojure.core/reduce` but given function `<f` is async. Carries thrown exception (will convert to `ExceptionInfo`) as result."
148+
[<f init coll]
149+
(go-loop [accu init, [item & rest-coll] coll]
150+
(if item
151+
(recur
152+
(<! (<f accu item))
153+
rest-coll)
154+
accu)))
155+
115156
(defn into
116157
"Like `core.async/into` but carries thrown exception (will convert to `ExceptionInfo`) as result."
117158
[coll ch]
118159
(reduce conj coll ch))
119160

120-
(defn smap
121-
"Applies async function `<f` on every item of seqs `xs` *chaining its execution to make sure its run sequentially*. All seqs of `xs` must have the same length. Returns vector of all results applying `<f`. Supports error handling.
161+
(defn awalk
162+
"Like `clojure.core/walk` but given function `<inner` and `<outer` are async. Execution with values of `form` can be unordered an for clojure (not clojurescript) in parallel. Carries thrown exception (will convert to `ExceptionInfo`) as result."
163+
[<inner <outer form]
164+
(go
165+
(cond
166+
(list? form)
167+
(<outer (apply list (<! (amap <inner form))))
122168

123-
Also see `amap`"
124-
[<f & xs]
125-
(go-loop [result [], xs xs]
126-
(if (ffirst xs)
169+
#?(:cljs (map-entry? form) :clj (instance? clojure.lang.IMapEntry form))
127170
(do
128-
(let [next-result
129-
(->> xs
130-
(mapv first)
131-
(apply <f)
132-
(<!))]
133-
134-
(recur
135-
(conj result next-result)
136-
(mapv next xs))))
137-
138-
result)))
139-
140-
(def chain smap)
141-
142-
(defn amap
143-
"Applies async function `<f` on every item of seqs `xs`. All seqs of `xs` must have the same length. Returns vector of all results applying `<f`. Supports error handling.
144-
145-
Also see `smap`"
146-
[<f & xs]
147-
(->> (apply clojure.core/map <f xs)
148-
(map vector)))
171+
(<! (<outer #?(:cljs
172+
(MapEntry.
173+
(<! (<inner (key form)))
174+
(<! (<inner (val form)))
175+
nil)
176+
177+
:clj
178+
(clojure.lang.MapEntry/create
179+
(<! (<inner (key form)))
180+
(<! (<inner (val form))))))))
181+
182+
(seq? form)
183+
(<! (<outer (<! (amap <inner form))))
184+
185+
(record? form)
186+
(<! (<outer (<! (areduce (fn [r x] (let [c (async/chan 1)] (async/take! (<inner x) #(conj r %)) c)) form form))))
187+
188+
(coll? form)
189+
(<! (<outer (clojure.core/into (empty form) (<! (amap <inner form)))))
190+
191+
:else
192+
(<! (<outer form)))))
193+
194+
(defn apostwalk
195+
"Like `clojure.core/postwalk` but given function `<f` is async. Execution with values of `form` can be unordered an for clojure (not clojurescript) in parallel. Carries thrown exception (will convert to `ExceptionInfo`) as result."
196+
[<f form]
197+
(awalk (partial apostwalk <f) <f form))
198+
199+
(defn aprewalk
200+
"Like `clojure.core/prewalk` but given function `<f` is async. Execution with values of `form` can be unordered an for clojure (not clojurescript) in parallel. Carries thrown exception (will convert to `ExceptionInfo`) as result."
201+
[<f form]
202+
(go
203+
(<!
204+
(awalk
205+
(partial aprewalk <f)
206+
#(let [c (async/chan 1)]
207+
(async/put! c (identity %))
208+
c)
209+
(<! (<f form))))))

0 commit comments

Comments
 (0)