Fork me on GitHub
#missionary
<
2023-11-13
>
telekid17:11:47

More questions in thread >

telekid17:11:59

(I'm just studying missionary, this isn't pressing.)

telekid17:11:14

tl;dr, I don't understand how cancellation propagates

Dustin Getz17:11:33

i dont think you should ever have to catch missionary.Cancelled, is that right Leo?

Dustin Getz17:11:43

you mean: today userland should never have to catch missionary.Cancelled, but in the future there may be a reason for userland to catch Cancelled?

leonoel17:11:57

no, I mean the opposite

👍 1
leonoel17:11:44

you have to care about Cancelled in ap today, but that's a bug

Dustin Getz17:11:03

under what circumstance exactly do we care

leonoel17:11:44

the continuation of ?< will throw Cancelled before switching

Dustin Getz17:11:30

today, m/?< ("switch") will cancel the old child branch, and let the terminal value (likely the exception) be seen by the parent, and then boot the new child branch

Dustin Getz17:11:12

the desired behavior is for the old child branch to be flushed for effect (resource disposal) but the terminal value is not seen, because the "switch" is effective immediately

leonoel17:11:16

we want to ignore everything produced by the previous branch after its cancellation

👍 1
Dustin Getz17:11:53

and this is justified by the idea that since a variable input has changed (causing the switch), seeing the terminal value is an inconsistency, as in a glitch?

Dustin Getz17:11:23

or is it simply justified by ergonomics, parent userland should not need a defensive try/catch everywhere

Dustin Getz17:11:48

(otherwsie the Cancellation would propagate too far and unwind the entire program, which is never correct the user's intent)

leonoel17:11:47

it feels wrong to have to catch Cancelled on switch because there is no real-world scenario requiring this

👀 1
leonoel17:11:31

there is also no good reason to delay the creation of the next branch due to a slow shutdown of the previous one

👍 1
Dustin Getz17:11:16

ah, under today's switch semantics the terminal value is required and awaited before we can switch

Dustin Getz17:11:21

I wanted to ask, why is this a discrete phenomenon only, but i remembered that m/cp didn't exist yet and when we worked out the semantics of m/cp is how we first understood how switch and cancellation should interact

Dustin Getz17:11:41

so m/cp was built with the right semantics in the first place, and updating m/ap was backlogged

Dustin Getz17:11:59

(the discrete phenomenon here being the idea of a delayed termination?)

leonoel17:11:00

first versions of cp actually were not immediate

leonoel17:11:33

the switches were slow due to network round trips

👍 1
Dustin Getz17:11:38

is it even possible for a continuous flow to have delayed termination?

leonoel17:11:04

sure, because you can derive a continuous flow from a discrete one

Dustin Getz17:11:45

ah, of course, the quickstart shows how to have a continous flow be cancelled but the response to the cancellation is not seen until (under the flow protocol) the flow notifies and then is consumed

Dustin Getz17:11:06

and under switch, we cancel and then stop listening, (though the machinery will consume the terminal value to drive resource cleanup)

telekid14:11:52

> the continuation of ?< will throw Cancelled before switching I think that this means I should be doing something like this, but of course it is illegal because one Cannot recur across try

telekid15:11:36

And for kicks I tried defining it as a continuous process (which is probably preferable anyway,) but modifying tempo still terminates the flow with Watch cancelled. (ignore this, I tested it incorrectly. Obviously cp isn't compatible with m/?<.)

leonoel15:11:17

cp is compatible with ?<

telekid15:11:11

Sorry, misread the docstring :face_palm: one of those mornings

telekid15:11:46

ah right, looks like it is amb that is incompatible with cp

leonoel15:11:32

this pattern is not correct because for each iteration of the loop another subscription to tempo will be created without cancelling the previous one

leonoel15:11:57

could you show an example of how this function is supposed to be used

telekid15:11:53

Sure, one moment

telekid15:11:02

Something like this:

;; Emit a keyword representing a midi event on each beat. If `tempo` increases, :kick-drum should emit more frequently.
(fn drum [tempo]
  (m/ap
   (m/amb (do (m/?< (beats tempo 0))
              :kick-drum))))
Or perhaps the effect would happen in a reducer, not sure

telekid15:11:40

(`:kick-drum` would more likely be e.g. a task that emits a midi note or something)

leonoel17:11:37

This pattern works. This is basically a discrete version of the with-cycle pattern, the cycle is needed to keep track of state through successive switches

(defn now [] (System/currentTimeMillis))

(defn variable-clock [<bpm]
  (m/ap
    (try (let [state (atom [0 (now)])
               [i ts bpm] (m/?< (m/latest conj (m/watch state) <bpm))
               target (+ ts (int (* 1000 (/ 60 bpm))))]
           (m/? (m/sleep (- target (now))))
           (reset! state [(inc i) target]) i)
         (catch missionary.Cancelled _ (m/amb)))))

(comment

  (def !tempo (atom 120))

  (def ps
    ((->> (variable-clock (m/watch !tempo))
       (m/reduce (fn [_ i] (prn i)) nil))
     prn prn))

  (reset! !tempo 60)

  (ps)

  )

telekid18:11:28

Ah, cool! Thank you, will play with it.

telekid18:11:50

https://gist.github.com/telekid/86bebd7f94073302e743abf01b148a8e. It prints midi notes at the given tempo and adjusts the length of notes proportionally. While this particular example isn't too hard to express imperatively (or in a traditional functional manner), more complex examples are tough to express and I can already see how missionary makes it a ton easier.

👏 1
telekid18:11:40

My next goal is to figure out how to model notes as resources that I can hand over to the supervision tree to avoid "hanging notes," where a midi on event occurs without a matching midi off event.

👍 1
leonoel18:11:21

please share !

telekid19:11:43

https://gist.github.com/telekid/86bebd7f94073302e743abf01b148a8e (just in case you didn't catch the link in my prev msg.) Will follow up when (if? ha) I figure out note modeling

👍 1
Dustin Getz19:11:07

related reference - https://www.cs.yale.edu/homes/hudak/Papers/HSoM.pdf has a midi intro as well. heads up the PDF is unfinished, book version is the final draft

telekid19:11:11

awesome, this has been on my reading list for a while

telekid19:11:17

I've taken half a dozen stabs of "express a live composition as a partially realized stream" over the past few years but always found myself ensnared by resource allocation and cleanup

telekid19:11:31

basically ending up with a tree of timers that are extremely hard to manage

telekid19:11:38

sound familiar? ha

🙂 1