| The basic idea is to provide a way for a transaction to call into 
transaction-aware libraries.  The libraries
| can register callbacks for if the transaction commits (to actually do any 
"O") and for if the transaction
| aborts (to re-buffer any "I" that the transaction has consumed).  In 
addition, a library providing access
| to another transactional abstraction (e.g. a database supporting 
transactions) can perform a 2-phase
| commit that means that the memory transaction and database transaction either 
both commit or both
| abort.

Yes, I have toyed with extending GHC's implementation of STM to support

        onCommit :: IO a -> STM ()

The idea is that onCommit would queue up an IO action to be performed when the 
transaction commits, but without any atomicity guarantee.  If the transaction 
retries, the action is discarded.  Now you could say
        atomic (do {
          xv <- readTVar x
          yv <- readTVar y
          if xv>yv then
                onCommit launchMissiles
             else return () })
and the missiles would only get launched when the transaction successfully 
commits.

This is pure programming convenience.  It's always possible to make an existing 
Haskell STM transaction that *returns* an IO action, which is performed by the 
caller, thus:

 dO { action <- atomic (do {
          xv <- readTVar x;
          yv <- readTVar y;
          if xv>yv then
                retur launchMissiles
             else return (return ()) }) ;
      action }

All onCommit does is make it more convenient.  Perhaps a *lot* more convenient.

I have also toyed with adding

        retryWith :: IO a -> STM ()

The idea here is that the transction is undone (i.e. just like the 'retry' 
combinator), then the specified action is performed, and then the transaction 
is retried.  Again no atomicity guarantee.  If there's an orElse involved, both 
actions would get done.

Unlike onCommit, onRetry adds new power.  Suppose you have a memory buffer, 
with an STM interface:
    getLine :: Buffer -> STM STring

This is the way to do transactional input: if there is not enough input, the 
transaction retries; and the effects of getLine aren't visible until the 
transaction commits.  The problem is that if there is not enough data in the 
buffer, getLine will retry; but alas there is no way at present to "tell" 
someone to fill the buffer with more data.

onRetry would fix that.  getLine could say
    if <not enough data> then retryWith <fill-buffer action>

It would also make it possible to count how many retries happened:
   atomic (<transaction> `orElse` retryWith <increment retry counter>)

I have not implemented either of these, but I think they'd be cool.

Simon

PS: I agree wholeheartedly with this:

| Of course, these solutions don't deal with the question of atomic blocks that 
want to perform output
| (e.g. to the console) and receive input in response to that.  My view at the 
moment is _that does not
| make sense in an atomic block_ -- the output and input can't be performed 
atomically because the
| intervening state must be visible for the user to respond to.
_______________________________________________
Haskell-Cafe mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/haskell-cafe

Reply via email to