Fork me on GitHub
#clojurescript
<
2020-03-20
>
lilactown20:03:57

I have a list of functions that take callbacks, and I want to exec them in order. e.g.

[proc1 proc2 proc3 ,,, procN]
and I want to exec:
(proc1 (fn [] (proc2 (fn [] (proc3 ,,,)))))

lilactown20:03:11

is there a cheap way to construct this callback chain?

nwjsmith21:03:57

Will (apply comp (reverse procs)) work?

nwjsmith21:03:22

ohh, those inner fns complicate it

nwjsmith21:03:26

:thinking_face:

OrdoFlammae21:03:42

Recursive macro is probably the way to go.

lilactown21:03:49

yeah I’m just going to punt on it for now

OrdoFlammae21:03:11

Why not just (proc1 (proc2 (proc3 ,,,)))?

OrdoFlammae21:03:22

Oh, wait, nvm.

OrdoFlammae21:03:27

I'd just go with a macro.

lilactown21:03:29

because proc<1,,N> are async

lilactown21:03:54

I’m writing a task-type similar to promises

lilactown21:03:14

so you write:

(def pipeline
 (->
  (task1)
  (t/join (task2))
  (t/join (task3))
  ,,,
  (t/join (taskN))))
and then sometime later:
(t/run! pipeline #(prn "done"))

lilactown21:03:19

right now, each t/join creates a new Task that calls run! when the previous task succeeds, building the callback chain on instantiation I was wondering if it would be better to store each task in a queue and wire up the callback chain on run!, but that seems harder

OrdoFlammae21:03:50

I wrote a basic macro that does what you want, I think. I'm not sure about the end-case.

OrdoFlammae21:03:34

(defmacro callbacks
  [proclist]
  (if (= (count proclist) 1)
    (first proclist)
    `(~(first proclist) (fn [] (callbacks ~(rest proclist))))))

(clojure.walk/macroexpand-all '(callbacks [:proc1 :proc2 :proc3 :proc4]))
;; => (:proc1 (fn* ([] (:proc2 (fn* ([] (:proc3 (fn* ([] :proc4)))))))))

OrdoFlammae21:03:52

There's probably a more efficient way using a loop, but that works.

Cameron21:03:53

Just curious lilactown (granted, I don't know if this is the most elegant) you are referring to something like this right

(defn run-callbacks [callbacks]
  (let [ run-callbacks-fn
        (->> callbacks
             reverse
             (reduce 
              (fn [inner-procs proc] 
                (fn [next] (proc (fn [] (inner-procs next)))))))]
    (run-callbacks-fn (fn [] ))))

(run-callbacks [(fn [callback] (println "One") (callback))
                (fn [callback] (println "Two") (callback))
                (fn [callback] (println "Three") (callback))])
;; user> 
;; One 
;; Two 
;; Three 

lilactown21:03:22

yep, that’s the gist of it!

lilactown21:03:32

that’s not too bad tbh. I think that creating the callback chain on instantiation will be more performant (no seqs involved), but using a list of callbacks might give more ability for runtime inspection

lilactown21:03:18

copying and pasting that to experiment with 😅