
Ryan Ingram said:
How can I implement the following operation efficiently in STM? Given a TVar "now",
waitFor t0 = do t <- readTVar now if (t < t0) then retry else return ()
This naive implementation has the problem that the transaction gets restarted every time "now" gets updated, even if the new value is still less than t0.
I'm not familiar with FRP, so this may be off the mark. Are you familiar with Control.Concurrent.STM.TVar.registerDelay? I realise your concept of time differs from that of registerDelay, but I suspect you'll need to use a similar approach.
One primitive that would be strong enough is this: retryUntil :: TVar a -> (a -> Bool) -> STM ()
although it would still do some computation every time "now" changed.
I don't think a primitive retryUntil would be able to do any better than the obvious implementation (which looks a lot like your waitFor).
The thought I originally had was to register the "waitFor" time with some helper which kept track of the current time and fired off a notice when it was ready. But the problem with that is that "retry" undoes all the work of setting that up; the goal is still to block, but I want a stronger blocking primitive.
That's essentially what registerDelay does. The key is that registering a timer must occur in the IO monad, outside the transaction that waits for it. I vaguely recall that there is at least one hackage library which is somewhat more sophisticated than registerDelay, so you might also want to look there.