<div dir="ltr">I had the same suggestion.  However, you then no longer need StateT, as ReaderT is enough.  Using a `ReaderT (TVar s) IO a` will allow atomic changes to the state s, along with interleaved IO when it's done safely rather than in the middle of a transaction.</div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Wed, Sep 1, 2021 at 11:17 AM Bryan Richter <<a href="mailto:b@chreekat.net">b@chreekat.net</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="auto">You've maybe already considered this, but what if the TVar is part of the state s? <div dir="auto"><br></div><div dir="auto">(StateT IO) can't give any guarantees about when or how the state is broadcast, but using STM within StateT actions still can. </div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Wed, 1 Sep 2021, 17.45 Olaf Klinke, <<a href="mailto:olf@aatal-apotheke.de" target="_blank">olf@aatal-apotheke.de</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Dear Café, <br>
<br>
I have a sequence of state-modifying computations<br>
<br>
action :: MonadUnliftIO m => StateT s m ()<br>
<br>
where the state s should be visible to other threads. Thus I created a<br>
TVar in which I keep track of this state s for other threads to read.<br>
<br>
The type system tells me it can't be done, which suggests I am using<br>
the wrong abstraction. The following type-checks but may be unsafe. <br>
<br>
import Control.Concurrent.STM<br>
import Control.Monad.IO.Unlift<br>
updateStateTVar :: MonadUnliftIO m => TVar s -> StateT s m () -> m ()<br>
updateStateTVar var action = withRunInIO (\inIO -> do<br>
    s0 <- atomically (readTVar var)<br>
    s1 <- inIO (execStateT action s0)<br>
    atomically (writeTVar var s1))<br>
<br>
Yet the splitting into readTVar and writeTVar is dangerous if several<br>
threads have read/write access to the same TVar. I was hoping to write<br>
the above using modifyTVar. However, the action essentially gives me a<br>
Kleisli map<br>
s -> m s<br>
which I somehow have to turn into an <br>
m (s -> s)<br>
but it is not possible in general. (The reverse works for any functor.)<br>
<br>
What should I do? <br>
* Switch to WriterT (Endo s) m?<br>
  This is not as powerful as StateT s m.<br>
* Do everything in the STM monad? But this disallows arbitrary IO<br>
because it would facilitate nested STM transactions. <br>
<br>
The code above is safe, I believe, if only one thread has read/write<br>
access and the others are read-only. Are there type-level abstractions<br>
of this kind? (I suppose one could easily make them with some<br>
newtypes.) <br>
<br>
Thanks in advance for any thoughts on this.<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>
_______________________________________________<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" 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>