[Haskell-cafe] Stronger STM primitives needed? Or am I just doing it wrong?

David Roundy droundy at darcs.net
Wed Apr 23 17:09:36 EDT 2008

On Wed, Apr 23, 2008 at 01:46:53PM -0700, Ryan Ingram wrote:
> On 4/23/08, David Roundy <droundy at darcs.net> wrote:
> > I'm confused as to how your retryUntil gains you anything.  If any of the
> > TVars used in the expensive_computation change while waiting for a retry,
> > then the expensive_computation will need to be done again.  If none of them
> > change, then we can skip the expensive_computation.
> Does the STM runtime do this?
> > i.e. how does your broken function using retryUntil differ from the
> > following?
> >
> > broken = atomically $ do
> >         v <- expensive_computation :: STM (TVar Int)
> >         vv <- readTVar v
> >         unless (vv > 50) retry
> If the STM runtime does the optimization you suggest, it's not
> different at all.

I doubt it does this, but my point is that you aren't suggesting a new
primitive, you're suggesting an improved runtime.  Once you've got your
improved runtime, this optimization is trivial, as far as I can tell.  And
without an improved runtime, your function is equivalent to this one.

> But consider this computation:
> > -- non-primitive retryUntil:
> > retryUntil v p = do
> >    x <- readVar v
> >    unless (p x) retry
> >
> > broken2 = atomically $ do
> >    (v1, v2) <- expensive_computation :: STM (TVar Int, TVar Int)
> >    retryUntil v1 (> 50)
> >    x <- expensive_computation2 :: STM Int
> >    retryUntil v2 (> x)
> If v1 succeeds and v2 fails, then v1 changes to some other value > 50,
> I am sure that the STM runtime as it stands now will re-run
> expensive_computation2.

I suppose it depends on how you rewrite the runtime.  Rather than your very
limited retryUntil + caching of results computed in the STM, why not make
this caching explicit, and allow users to write their own more complicated
variants of retryUntil? e.g.

retryUntil2 :: TVar a -> TVar b -> (a -> b -> Bool) -> IO ()

A simple primitive to do this (in combination with a totally rewritten STM
runtime) would be

subatomically :: ReadOnlySTM a -> STM ()

which would run a STM computation that is guaranteed to have no
side-effects (i.e. can't write to TVars) and ignore its results (and let
the runtime know that the results have been ignored).  Then your
extra-fancy retryUntil could simply be.

retryUntil v p = subatomically $
                 do x <- readVarRO v
                    unless (p x) retryRO

The only thing that is special about your retryUntil is that it does not
allow the modification of TVars.

On the other hand, I suspect the whole issue is silly.  Is it ever actually
wise to do an expensive calculation in the STM monad? That seems like it's
guaranteed to be a performance nightmare.
David Roundy
Department of Physics
Oregon State University

More information about the Haskell-Cafe mailing list