<div dir="auto">How about using a read-write lock?<div dir="auto"><br></div><div dir="auto">data Locked a = Locked { lockVar :: TVar Bool, valueVar :: TVar a }</div><div dir="auto"><br></div><div dir="auto">new :: a -> IO (Locked a)</div><div dir="auto">new val = Locked <$> newTVarIO False <*> newTVarIO val</div><div dir="auto"><br></div><div dir="auto">-- lock blocks until unlocked</div><div dir="auto">lock, unlock :: Locked a -> STM ()</div><div dir="auto"><br></div><div dir="auto">-- never blocks</div><div dir="auto">read :: Locked a -> STM a</div><div dir="auto"><br></div><div dir="auto">-- blocks until unlocked</div><div dir="auto">write :: Locked a -> a -> STM ()</div><div dir="auto"><br></div><div dir="auto">When you want to apply your effectful state trasition `f :: s -> m s`:</div><div dir="auto"><br></div><div dir="auto">l <- ask</div><div dir="auto">s <- liftIO . atomically $ lock l *> read l</div><div dir="auto">s' <- f s</div><div dir="auto">liftIO . atomically $ write l s' *> unlock l</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, 3 Sep 2021, 3:46 am Olaf Klinke, <<a href="mailto:olf@aatal-apotheke.de">olf@aatal-apotheke.de</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">On Fri, 2021-09-03 at 00:00 +0800, YueCompl wrote:<br>
> 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>
<br>
To be concrete, my state is a collection of time stamped values, where<br>
the monoid operation overwrites old values with new ones. <br>
But I need to know the current state (x,t) to determine the "mutation",<br>
because I'll be asking questions like "server, tell me if there is a<br>
value of x newer than t." <br>
Any observer whose initial state is synchronized with the worker thread<br>
can in principle re-construct the worker's internal state by observing<br>
the stream of emitted "mutations". <br>
<br>
The most general abstraction would be that of a monoid action on a<br>
type, but in my case the monoid (mutations) and the mutated type are<br>
identical. <br>
<br>
act :: m -> a -> a<br>
act memtpy = id<br>
act (x <> y) = act x . act y -- monoid homomorphism<br>
act (x <> x) = act x         -- idempotent<br>
<br>
Olaf<br>
<br>
_______________________________________________<br>
Haskell-Cafe mailing list<br>
To (un)subscribe, modify options or view archives go to:<br>
<a href="http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe" rel="noreferrer noreferrer" target="_blank">http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe</a><br>
Only members subscribed via the mailman list are allowed to post.</blockquote></div>