This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2024-02-06
Channels
- # aleph (43)
- # announcements (11)
- # babashka (35)
- # beginners (70)
- # calva (4)
- # cider (8)
- # clerk (15)
- # clojure (192)
- # clojure-dev (7)
- # clojure-europe (44)
- # clojure-nl (2)
- # clojure-norway (65)
- # clojure-uk (4)
- # code-reviews (4)
- # conjure (1)
- # cursive (41)
- # data-science (1)
- # datomic (8)
- # emacs (7)
- # fulcro (13)
- # humbleui (17)
- # hyperfiddle (53)
- # kaocha (4)
- # malli (7)
- # missionary (17)
- # music (1)
- # obb (1)
- # off-topic (8)
- # polylith (1)
- # portal (3)
- # releases (11)
- # shadow-cljs (36)
- # squint (4)
- # tools-deps (4)
I was reading through the wiki pages and I'm wondering: The "Iterative queries" page mentions that recursively building successive flows is a bad idea since it might blow the stack. In the "Retry with backoff" example:
(defn backoff [request delays]
(if-some [[delay & delays] (seq delays)]
(m/sp
(try (m/? request)
(catch Exception e
(if (-> e ex-data :worth-retrying)
(do (m/? (m/sleep delay))
(m/? (backoff request delays)))
(throw e)))))
request))
we're limiting the number of delays to 5 so this is not a concern here. But would it not be better to explicitly use a loop
-`recur` solution here too? That would allow delays to be unbounded.(defn backoff [request delays]
(m/sp
(loop [delays (seq delays)]
(if-some [response (try (m/? request)
(catch Exception e
(when-not (-> e ex-data :worth-retrying)
(throw e))))]
response
(if-some [[delay & delays] delays]
(do (m/? (m/sleep delay)) (recur delays))
(throw (ex-info "Too many attempts." {:request request})))))))
Just checking - is (m/?> m/none)
equivalent to (m/amb)
in an ap
block?
For context I was looking at this example in the rxjava comparison:
(defn feed->flow [feed]
(let [mbx (m/mbx)]
(.register feed (reify SomeListener
(priceTick [event] (mbx [:val event]) (when (.isLast event) (mbx [:done])))
(error [e] (mbx [:err e]))))
(m/ap (loop [[t v] (m/? mbx)]
(case t
:val (if (m/?> (m/seed [true false])) v (recur (m/? mbx)))
:err (throw e)
:done (m/?> m/none))))))
yes. also (m/?> (m/seed [true false]))
is equivalent to (m/amb true false)
- the latter is sugar over the former.
Ah okay that makes a lot of sense. amb
did seem like something that could be recreated by the other primitives.
amb
is short for "ambiguous" evaluation - popularized by SICP (but predates it) https://mitp-content-server.mit.edu/books/content/sectbyfn/books_pres_0/6515/sicp.zip/full-text/book/book-Z-H-28.html#%_sec_4.3
ap
is "ambiguous process" - an evaluation context that allows ambiguous evaluation
absolve
& attempt
are inspired by ZIO https://zio.dev/1.0.18/overview/overview_handling_errors/
On line 9, I'm trying to cancel the sleep. I know there's ways around this (like race on the sleep with something else), but is there a way to explicitly cancel a task? If not, is there a reason? I'm assuming it might break some constructs...
It's not possible because the composition model never exposes the process handle to the user. (m/sleep delay)
is a pure function, it has no effect. The sleep is performed on (m/? wait-for-next)
, so only the parent process (i.e. the outer sp
) has access to the cancellation signal