<div>> broken2 = atomically $ do<br>> (v1, v2) <- expensive_computation :: STM (TVar Int, TVar Int)<br>> retryUntil v1 (> 50)<br>> x <- expensive_computation2 :: STM Int<br>> retryUntil v2 (> x)</div>
<div> </div>
<div>Ah. I think I see now. I had thought you were trying to give more power to the primitive than you are.</div>
<div> </div>
<div>But I'm still finding the example confusing, in that expensive_computation2 is in STM, and thus isn't pure. The point, I suppose, would rather be to assert that retryUntil v2 (> x) depends on what v2 depends on, and what x depends on, but *not* on what v1 depends on, and thus to retry only when the appropriate portion of the dependency tree changed.</div>
<div> </div>
<div>However, in this case, that still doesn't buy you anything, I think, because from the information given, one can't disentangle what v1 and v2 depend on?</div>
<div> </div>
<div>I hope I'm somewhat closer to the mark here.</div>
<div>--S<br><br> </div>
<div><span class="gmail_quote">On 4/23/08, <b class="gmail_sendername">Ryan Ingram</b> <<a href="mailto:ryani.spam@gmail.com">ryani.spam@gmail.com</a>> wrote:</span>
<blockquote class="gmail_quote" style="PADDING-LEFT: 1ex; MARGIN: 0px 0px 0px 0.8ex; BORDER-LEFT: #ccc 1px solid">On 4/23/08, Sterling Clover <<a href="mailto:s.clover@gmail.com">s.clover@gmail.com</a>> wrote:<br>> But expensive_computation2 is in STM. This means that it *should* be rerun,<br>
> no? Between the first run and the retry, the result of<br>> expensive_computation2 may well have changed.<br><br>Ah, but that's not true; the main "good thing" about retry is that you<br>don't have to keep running the computation; instead you wait until<br>
something that you accessed in your transaction log changes and -then-<br>you rerun it. Right now the transaction log for "retry" only contains<br>"read from variable X" (for some list of variables). But it could<br>
instead contain "read from variable X" and "read from variable X using<br>retryUntil with predicate p which gave result True". Then we have a<br>"smarter" log which can use the pure predicate p to give more<br>
information about whether or not the whole transaction can run or<br>whether it is just guaranteed to fail again. If we know a transaction<br>is guaranteed to fail, we can skip running it because we know it will<br>not commit.<br>
<br>Given the semantics of retryUntil, it is impossible that changing v1<br>affects the results of running this STM computation -unless- it or<br>something else prior in the computation read from v1, or the result of<br>the predicate changes.<br>
<br>No spooky-action-at-a-distance is possible. David's more general<br>"subatomically" primitive would achieve the same results; the proof is<br>that<br>(1) no side effects can be caused by the subatomic action, that is, no<br>
writes happen which could change future reads.<br>(2) the result of the computation is ignored -except- for whether it<br>retries or returns, that is, it can't affect the control flow of the<br>rest of the transaction.<br>
<br>So, if have a transaction T that is waiting inside "retry" for a<br>variable that it read to change, and a variable that is only accessed<br>in a "subatomic" part of T is changed, we can try running the<br>
subatomic computation first. Here are the four cases:<br><br>1) The subatomic computation succeeded before and still succeeded.<br>Then we know the end result of the computation is unaffected, and will<br>still retry. No need to do anything.<br>
2) The subatomic computation succeeded before and now fails (calls<br>'retry' or retryRO'). Then we know that the computation will now fail<br>at this earlier point. Mark the change to "fail" in the transaction<br>
log and leave the computation in the "waiting for retry" state.<br>3) The subatomic computation failed before and still fails. See (1)<br>4) The subatomic computation failed before and now succeeds. The<br>result of the entire computation can change, we should now re-run the<br>
entire computation.<br><br>-- ryan<br></blockquote></div><br>