This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-08-02
Channels
- # announcements (11)
- # aws (3)
- # babashka (34)
- # beginners (20)
- # biff (2)
- # calva (3)
- # cherry (29)
- # cider (6)
- # cljs-dev (9)
- # clojure (124)
- # clojure-europe (12)
- # clojure-norway (5)
- # clojure-uk (2)
- # clojurescript (32)
- # conjure (11)
- # datalevin (1)
- # datomic (16)
- # deps-new (1)
- # etaoin (6)
- # holy-lambda (10)
- # honeysql (28)
- # hyperfiddle (21)
- # jackdaw (2)
- # jobs (2)
- # leiningen (15)
- # missionary (12)
- # off-topic (132)
- # other-languages (1)
- # pathom (13)
- # rdf (10)
- # re-frame (8)
- # reagent (5)
- # releases (1)
- # remote-jobs (4)
- # shadow-cljs (32)
- # tools-deps (6)
- # vim (15)
- # xtdb (24)
I recently took the throttle
function from the wiki and it does what I need but I’m having a hard time really understanding the role of each missionary function in it. I wonder if some code comments in that function could be added to explain? https://github.com/leonoel/missionary/wiki/Debounce-and-Throttle#throttle
In particular the nested amb>
and how relieve
works is not quite clear to me
Relieve turns a discrete flow into a continuous one You sample it, then the outer amb returns the forms in a flow in order, so first x, then sleep. The inner amb fails, which means that the entire computation is discarded, going back to the next available sample from the input
Thanks. The inner amb
failing and the consequences of that are a bit unclear still but the relieve
and sample thing was very insightful!
maybe the comments make it more readable:
(defn throttle [dur >in]
(m/ap
(let [x (m/?> (m/relieve {} >in))]
(m/amb> ;; sequentially in an amb
x ;; emit x
(do (m/? (m/sleep dur)) ;; await sleep
(m/amb>)))))) ;; die
Simply, (m/relieve {}) means "don't block producers - discard stale values" m/relieve is a dangerous primitive, yes it converts a discrete flow into a continuous flow with a reducing fn BUT it does so by consuming the upstream flow as fast as possible and dumping it straight into the accumulator. In other words it "relieves" backpressure. This is appropriate for event sources like user interactions (typing into a dom input) because you only care about the freshest value and you never want your backpressure to slow down the user from typing. You lose the ability to run discrete effects on each discrete event, which for user typing into an input is fine, you only care about the freshest value and you don't care to see each intermediate keystroke. HOWEVER, by disabling backpressure you've ... lost all the benefits of backpressure, the whole point of backpressure is to tell the producer to slow down and prevent the system from getting too stressed the dangerous part is that m/relieve can be used to create "heaters" like this monster, which will turn your fan on while counting as fast as it can:
(->> (m/ap (loop [] (m/amb (m/? (m/sleep 0 1)) (recur))))
(m/reductions + 0)
(m/relieve {}))
Here is a video of the heater: https://www.loom.com/share/4406782e7a29487d8186eda86f8ef17bThe safe way to turn a discrete flow into continuous flow is m/reductions with m/latest:
(tests
(def <counter (->> (m/ap (loop [] (m/amb (m/? (m/sleep 0 1)) (recur))))
(m/reductions + 0)
(m/latest identity)))
(def !it (<counter #(! ::notify) #(! ::terminate)))
% := ::notify
@!it := 1
% := ::notify
@!it := 2
% := ::notify
@!it := 3
(!it))
✅✅✅✅✅✅
This counter is backpressured, it will count as fast as the consumer samplesExperiment for docs - https://nextjournal.com/a/4HAyM7xaC6MYmQ24eukaYg/
The experience was not good enough. I think maybe this is the old product though, possibly Clerk is better but not hosted afaik
i am now imaging a discord eval-bot paired with RCF; and a nice discord logger which can link to a message or range of messages
Are you aware of #clerk channel?