missionary 2025-04-26

(I guess I should also add, I do have an implementation that does behave the way I want, it's the loop/recur version that doesn't and it surprised me. If you replace the (def cancel! ,,,) with this implementation, it behaves as desired:

(def cancel! ((m/reduce (fn [_ x] (prn x)) nil
                            (m/cp (let [sig <value-sig
                                        [wait? value :as ret] (m/?< sig)]
                                    (if-not wait?
                                      ret
                                      (if (nil? value)
                                        [true nil]
                                        (let [!rewind-me (atom false)]
                                          (if (m/?< (m/watch !rewind-me))
                                            [false value]
                                            (if (m/?< <continue-sig)
                                              (reset! !rewind-me true)
                                              [true nil]))))))))

If you need to describe an actual circular dependency, using a mutable reference is the way to go. I don't quite get what problem you're trying to solve but feel free to propose better solutions, I don't have a clear path forward yet https://github.com/leonoel/missionary/issues/99

My graph is a DAG, this achieves "synchronized start" when multiple input edges to the dag (atoms) are updated, conceptually, at the same time. I have to set the <continue-sig's underlying to atom to false, update multiple values with [true <value>] so they'll propagate the delay, then reset! the <continue-sig's underlying atom to true, at which time all delayed computations unblock simultaneously and values begin to propagate again with [false ,,,] in the front.

For a single atom update, you just set the input atom to [false ,,,] and leave the <continual-signal's atom alone (it will have a value of true, but it should have no subscribers).