<html><head><meta http-equiv="Content-Type" content="text/html; charset=us-ascii"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class="">It's a bit sad that I'm not so mathematically minded to understand you in that abstract level. But I have a more imperative solution in my mind, wrt the question:<div class=""><br class=""></div><div class=""><blockquote type="cite" class="">"server, tell me if there is a value of x newer than t." </blockquote></div><div class=""><br class=""></div><div class="">and do further mutate-or-giveup, like this:</div><div class=""><br class=""></div><div class=""><div style="color: rgb(212, 190, 152); background-color: rgb(23, 24, 24); font-family: Menlo, Monaco, "Courier New", monospace; line-height: 18px; white-space: pre;" class=""><br class=""><div class=""><span style="color: #cc524b;" class="">data</span><span style="color: #d4bfa0;" class=""> </span><span style="color: #6b95c5;" class="">ValueNode</span><span style="color: #d4bfa0;" class=""> </span><span style="color: #82aed8;" class="">a</span><span style="color: #d4bfa0;" class=""> </span><span style="color: #cc524b;font-weight: bold;" class="">=</span><span style="color: #d4bfa0;" class=""> </span><span style="color: #cca143;" class="">ValueNode</span></div><div class=""><span style="color: #d4bfa0;" class="">  </span><span style="color: #cca143;" class="">{</span><span style="color: #d4bfa0;" class=""> </span><span style="color: #cca143;" class="">node'value</span><span style="color: #d4bfa0;" class=""> </span><span style="color: #cc524b;font-weight: bold;" class="">::</span><span style="color: #d4bfa0;" class=""> </span><span style="color: #82aed8;" class="">a</span>,</div><div class=""><span style="color: #d4bfa0;" class="">    </span><span style="color: #cca143;" class="">node'timestamp</span><span style="color: #d4bfa0;" class=""> </span><span style="color: #cc524b;font-weight: bold;" class="">::</span><span style="color: #d4bfa0;" class=""> </span><span style="color: #6b95c5;" class="">Timestamp</span>,</div><div class=""><span style="color: #d4bfa0;" class="">    </span><span style="color: #cca143;" class="">node'next</span><span style="color: #d4bfa0;" class=""> </span><span style="color: #cc524b;font-weight: bold;" class="">::</span><span style="color: #d4bfa0;" class=""> </span><span style="color: #6b95c5;" class="">ValueSink</span><span style="color: #d4bfa0;" class=""> </span><span style="color: #82aed8;" class="">a</span></div><div class=""><span style="color: #d4bfa0;" class="">  </span><span style="color: #cca143;" class="">}</span></div><br class=""><div class=""><span style="color: #cc524b;" class="">type</span><span style="color: #d4bfa0;" class=""> </span><span style="color: #6b95c5;" class="">ValueSink</span><span style="color: #d4bfa0;" class=""> </span><span style="color: #82aed8;" class="">a</span><span style="color: #d4bfa0;" class=""> </span><span style="color: #cc524b;font-weight: bold;" class="">=</span><span style="color: #d4bfa0;" class=""> </span><span style="color: #6b95c5;" class="">TMVar</span><span style="color: #d4bfa0;" class=""> </span>(<span style="color: #6b95c5;" class="">ValueNode</span><span style="color: #d4bfa0;" class=""> </span><span style="color: #82aed8;" class="">a</span>)</div><br class=""><div class=""><span style="color: #cc524b;" class="">type</span><span style="color: #d4bfa0;" class=""> </span><span style="color: #6b95c5;" class="">Timestamp</span><span style="color: #d4bfa0;" class=""> </span><span style="color: #cc524b;font-weight: bold;" class="">=</span><span style="color: #d4bfa0;" class=""> </span><span style="color: #6b95c5;" class="">Int</span></div><br class=""><div class=""><span style="color: #66a89d;" class="">seekTail</span><span style="color: #96b946;" class=""> </span><span style="color: #cc524b;font-weight: bold;" class="">::</span><span style="color: #96b946;" class=""> </span><span style="color: #6b95c5;" class="">ValueSink</span><span style="color: #96b946;" class=""> </span><span style="color: #82aed8;" class="">a</span><span style="color: #96b946;" class=""> </span><span style="color: #cc524b;font-weight: bold;" class="">-></span><span style="color: #96b946;" class=""> </span><span style="color: #6b95c5;" class="">STM</span><span style="color: #96b946;" class=""> </span>(<span style="color: #6b95c5;" class="">ValueSink</span><span style="color: #96b946;" class=""> </span><span style="color: #82aed8;" class="">a</span>,<span style="color: #96b946;" class=""> </span><span style="color: #6b95c5;" class="">Maybe</span><span style="color: #96b946;" class=""> </span>(<span style="color: #6b95c5;" class="">ValueNode</span><span style="color: #96b946;" class=""> </span><span style="color: #82aed8;" class="">a</span>))</div><div class=""><span style="color: #d4bfa0;" class="">seekTail sink </span><span style="color: #cc524b;font-weight: bold;" class="">=</span><span style="color: #d4bfa0;" class=""> go sink </span><span style="color: #cca143;" class="">Nothing</span></div><div class=""><span style="color: #d4bfa0;" class="">  </span><span style="color: #cc524b;" class="">where</span></div><div class=""><span style="color: #d4bfa0;" class="">    go ref ancestor </span><span style="color: #cc524b;font-weight: bold;" class="">=</span></div><div class=""><span style="color: #d4bfa0;" class="">      tryReadTMVar ref </span><span style="color: #a3d349;" class="">>>=</span><span style="color: #d4bfa0;" class=""> </span><span style="color: #cc524b;font-weight: bold;" class="">\</span><span style="color: #cc524b;" class="">case</span></div><div class=""><span style="color: #d4bfa0;" class="">        </span><span style="color: #cca143;" class="">Nothing</span><span style="color: #d4bfa0;" class=""> </span><span style="color: #cc524b;font-weight: bold;" class="">-></span><span style="color: #d4bfa0;" class=""> return </span>(<span style="color: #d4bfa0;" class="">ref</span>,<span style="color: #d4bfa0;" class=""> ancestor</span>)</div><div class=""><span style="color: #d4bfa0;" class="">        </span><span style="color: #cca143;" class="">Just</span><span style="color: #d4bfa0;" class=""> self</span><span style="color: #cca143;" class="">@</span>(<span style="color: #cca143;" class="">ValueNode</span><span style="color: #d4bfa0;" class=""> _ _ nxt</span>)<span style="color: #d4bfa0;" class=""> </span><span style="color: #cc524b;font-weight: bold;" class="">-></span><span style="color: #d4bfa0;" class=""> go nxt </span><span style="color: #a3d349;" class="">$</span><span style="color: #d4bfa0;" class=""> </span><span style="color: #cca143;" class="">Just</span><span style="color: #d4bfa0;" class=""> self</span></div><br class=""><div class=""><span style="color: #66a89d;" class="">updateValue</span><span style="color: #96b946;" class=""> </span><span style="color: #cc524b;font-weight: bold;" class="">::</span></div><div class=""><span style="color: #96b946;" class="">  </span><span style="color: #cc524b;font-style: italic;" class="">forall</span><span style="color: #96b946;" class=""> </span><span style="color: #82aed8;" class="">a</span><span style="color: #96b946;" class=""> </span><span style="color: #82aed8;" class="">m</span><span style="color: #cc524b;font-weight: bold;" class="">.</span></div><div class=""><span style="color: #96b946;" class="">  </span><span style="color: #6b95c5;" class="">MonadIO</span><span style="color: #96b946;" class=""> </span><span style="color: #82aed8;" class="">m</span><span style="color: #96b946;" class=""> </span><span style="color: #cc524b;font-weight: bold;" class="">=></span></div><div class=""><span style="color: #96b946;" class="">  </span>(<span style="color: #6b95c5;" class="">Maybe</span><span style="color: #96b946;" class=""> </span>(<span style="color: #82aed8;" class="">a</span>,<span style="color: #96b946;" class=""> </span><span style="color: #6b95c5;" class="">Timestamp</span>)<span style="color: #96b946;" class=""> </span><span style="color: #cc524b;font-weight: bold;" class="">-></span><span style="color: #96b946;" class=""> </span><span style="color: #82aed8;" class="">m</span><span style="color: #96b946;" class=""> </span>(<span style="color: #82aed8;" class="">a</span>,<span style="color: #96b946;" class=""> </span><span style="color: #6b95c5;" class="">Timestamp</span>))<span style="color: #96b946;" class=""> </span><span style="color: #cc524b;font-weight: bold;" class="">-></span></div><div class=""><span style="color: #96b946;" class="">  </span><span style="color: #6b95c5;" class="">ValueSink</span><span style="color: #96b946;" class=""> </span><span style="color: #82aed8;" class="">a</span><span style="color: #96b946;" class=""> </span><span style="color: #cc524b;font-weight: bold;" class="">-></span></div><div class=""><span style="color: #96b946;" class="">  </span><span style="color: #82aed8;" class="">m</span><span style="color: #96b946;" class=""> </span>()</div><div class=""><span style="color: #d4bfa0;" class="">updateValue f sink </span><span style="color: #cc524b;font-weight: bold;" class="">=</span><span style="color: #d4bfa0;" class=""> </span><span style="color: #cc524b;" class="">do</span></div><div class=""><span style="color: #d4bfa0;" class="">  </span>(<span style="color: #d4bfa0;" class="">tailRef</span>,<span style="color: #d4bfa0;" class=""> tailNode</span>)<span style="color: #d4bfa0;" class=""> </span><span style="color: #cc524b;font-weight: bold;" class=""><-</span><span style="color: #d4bfa0;" class=""> liftIO </span><span style="color: #a3d349;" class="">$</span><span style="color: #d4bfa0;" class=""> atomically </span><span style="color: #a3d349;" class="">$</span><span style="color: #d4bfa0;" class=""> seekTail sink</span></div><div class=""><span style="color: #d4bfa0;" class="">  </span><span style="color: #cc524b;" class="">case</span><span style="color: #d4bfa0;" class=""> tailNode </span><span style="color: #cc524b;" class="">of</span></div><div class=""><span style="color: #d4bfa0;" class="">    </span><span style="color: #cca143;" class="">Nothing</span><span style="color: #d4bfa0;" class=""> </span><span style="color: #cc524b;font-weight: bold;" class="">-></span><span style="color: #d4bfa0;" class=""> </span><span style="color: #cc524b;" class="">do</span></div><div class=""><span style="color: #d4bfa0;" class="">      </span>(<span style="color: #d4bfa0;" class="">myVal</span>,<span style="color: #d4bfa0;" class=""> myTs</span>)<span style="color: #d4bfa0;" class=""> </span><span style="color: #cc524b;font-weight: bold;" class=""><-</span><span style="color: #d4bfa0;" class=""> f </span><span style="color: #cca143;" class="">Nothing</span></div><div class=""><span style="color: #d4bfa0;" class="">      liftIO </span><span style="color: #a3d349;" class="">$</span></div><div class=""><span style="color: #d4bfa0;" class="">        atomically </span><span style="color: #a3d349;" class="">$</span><span style="color: #d4bfa0;" class=""> </span><span style="color: #cc524b;" class="">do</span></div><div class=""><span style="color: #d4bfa0;" class="">          nxt </span><span style="color: #cc524b;font-weight: bold;" class=""><-</span><span style="color: #d4bfa0;" class=""> newEmptyTMVar</span></div><div class=""><span style="color: #d4bfa0;" class="">          void </span><span style="color: #a3d349;" class="">$</span><span style="color: #d4bfa0;" class=""> tryPutTMVar tailRef </span><span style="color: #a3d349;" class="">$</span><span style="color: #d4bfa0;" class=""> </span><span style="color: #cca143;" class="">ValueNode</span><span style="color: #d4bfa0;" class=""> myVal myTs nxt</span></div><div class=""><span style="color: #d4bfa0;" class="">    </span><span style="color: #cca143;" class="">Just</span><span style="color: #d4bfa0;" class=""> </span>(<span style="color: #cca143;" class="">ValueNode</span><span style="color: #d4bfa0;" class=""> seenVal seenTs seenNxt</span>)<span style="color: #d4bfa0;" class=""> </span><span style="color: #cc524b;font-weight: bold;" class="">-></span><span style="color: #d4bfa0;" class=""> </span><span style="color: #cc524b;" class="">do</span></div><div class=""><span style="color: #d4bfa0;" class="">      </span>(<span style="color: #d4bfa0;" class="">myVal</span>,<span style="color: #d4bfa0;" class=""> myTs</span>)<span style="color: #d4bfa0;" class=""> </span><span style="color: #cc524b;font-weight: bold;" class=""><-</span><span style="color: #d4bfa0;" class=""> f </span><span style="color: #a3d349;" class="">$</span><span style="color: #d4bfa0;" class=""> </span><span style="color: #cca143;" class="">Just</span><span style="color: #d4bfa0;" class=""> </span>(<span style="color: #d4bfa0;" class="">seenVal</span>,<span style="color: #d4bfa0;" class=""> seenTs</span>)</div><div class=""><span style="color: #d4bfa0;" class="">      newNxt </span><span style="color: #cc524b;font-weight: bold;" class=""><-</span><span style="color: #d4bfa0;" class=""> liftIO newEmptyTMVarIO</span></div><div class=""><span style="color: #d4bfa0;" class="">      </span><span style="color: #cc524b;" class="">let</span><span style="color: #d4bfa0;" class=""> newTail </span><span style="color: #cc524b;font-weight: bold;" class="">=</span><span style="color: #d4bfa0;" class=""> </span><span style="color: #cca143;" class="">ValueNode</span><span style="color: #d4bfa0;" class=""> myVal myTs newNxt</span></div><br class=""><div class=""><span style="color: #96b946;" class="">          </span><span style="color: #66a89d;" class="">putAsNewTailOrDiscard</span><span style="color: #96b946;" class=""> </span><span style="color: #cc524b;font-weight: bold;" class="">::</span><span style="color: #96b946;" class=""> </span><span style="color: #6b95c5;" class="">ValueSink</span><span style="color: #96b946;" class=""> </span><span style="color: #82aed8;" class="">a</span><span style="color: #96b946;" class=""> </span><span style="color: #cc524b;font-weight: bold;" class="">-></span><span style="color: #96b946;" class=""> </span><span style="color: #6b95c5;" class="">STM</span><span style="color: #96b946;" class=""> </span>()</div><div class=""><span style="color: #d4bfa0;" class="">          putAsNewTailOrDiscard nodeRef </span><span style="color: #cc524b;font-weight: bold;" class="">=</span></div><div class=""><span style="color: #d4bfa0;" class="">            putTMVar nodeRef newTail </span><span style="color: #96b946;font-weight: bold;" class="">`</span><span style="color: #96b946;" class="">orElse</span><span style="color: #96b946;font-weight: bold;" class="">`</span><span style="color: #d4bfa0;" class=""> yetOther'sTail</span></div><div class=""><span style="color: #d4bfa0;" class="">            </span><span style="color: #cc524b;" class="">where</span></div><div class=""><span style="color: #d4bfa0;" class="">              yetOther'sTail </span><span style="color: #cc524b;font-weight: bold;" class="">=</span><span style="color: #d4bfa0;" class=""> </span><span style="color: #cc524b;" class="">do</span></div><div class=""><span style="color: #d4bfa0;" class="">                </span>(<span style="color: #cca143;" class="">ValueNode</span><span style="color: #d4bfa0;" class=""> _other'sVal other'sTs other'sNxt</span>)<span style="color: #d4bfa0;" class=""> </span><span style="color: #cc524b;font-weight: bold;" class=""><-</span></div><div class=""><span style="color: #d4bfa0;" class="">                  readTMVar nodeRef</span></div><div class=""><span style="color: #d4bfa0;" class="">                </span><span style="color: #cc524b;" class="">if</span><span style="color: #d4bfa0;" class=""> other'sTs </span><span style="color: #a3d349;" class="">>=</span><span style="color: #d4bfa0;" class=""> myTs</span></div><div class=""><span style="color: #d4bfa0;" class="">                  </span><span style="color: #cc524b;" class="">then</span><span style="color: #d4bfa0;" class=""> return </span>()</div><div class=""><span style="color: #d4bfa0;" class="">                  </span><span style="color: #cc524b;" class="">else</span><span style="color: #d4bfa0;" class=""> putAsNewTailOrDiscard other'sNxt</span></div><br class=""><div class=""><span style="color: #d4bfa0;" class="">      liftIO </span><span style="color: #a3d349;" class="">$</span><span style="color: #d4bfa0;" class=""> atomically </span><span style="color: #a3d349;" class="">$</span><span style="color: #d4bfa0;" class=""> putAsNewTailOrDiscard seenNxt</span></div><br class=""><div class=""><span style="color: #7e6b5f;" class="">-- Each concurrent thread is supposed to have its local 'ValueSink' reference</span></div><div class=""><span style="color: #7e6b5f;" class="">-- "cached" over time, but keep in mind that for any such thread who is slow</span></div><div class=""><span style="color: #7e6b5f;" class="">-- in unfolding the value stream, the historical values will pile up in heap.</span></div><br class=""></div></div><div class=""><br class=""><div><br class=""><blockquote type="cite" class=""><div class="">On 2021-09-03, at 01:42, Olaf Klinke <<a href="mailto:olf@aatal-apotheke.de" class="">olf@aatal-apotheke.de</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="">On Fri, 2021-09-03 at 00:00 +0800, YueCompl wrote:<br class=""><blockquote type="cite" class="">Um, I'm not sure I understand your case right, but if the "mutation" instead of the "mutated result" can be (might non-trivially) computed from a possibly outdated state, and the "mutation" can be trivially applied, I think `modifyTVar'` is the way to go. `readTVar` can be used to obtain an almost up-to-date state on demand, at low frequency.<br class=""></blockquote><br class="">To be concrete, my state is a collection of time stamped values, where<br class="">the monoid operation overwrites old values with new ones. <br class="">But I need to know the current state (x,t) to determine the "mutation",<br class="">because I'll be asking questions like "server, tell me if there is a<br class="">value of x newer than t." <br class="">Any observer whose initial state is synchronized with the worker thread<br class="">can in principle re-construct the worker's internal state by observing<br class="">the stream of emitted "mutations". <br class=""><br class="">The most general abstraction would be that of a monoid action on a<br class="">type, but in my case the monoid (mutations) and the mutated type are<br class="">identical. <br class=""><br class="">act :: m -> a -> a<br class="">act memtpy = id<br class="">act (x <> y) = act x . act y -- monoid homomorphism<br class="">act (x <> x) = act x         -- idempotent<br class=""><br class="">Olaf<br class=""><br class=""></div></div></blockquote></div><br class=""></div></body></html>