I think how you want to do this depends on the motivation of why you want to rollback.  Note that rolling back based on information *inside* the transaction means that the transaction must be consistent to successfully rollback.  If you want to trigger rolling back from *outside* the transaction you can do something like this:

atomicallyWithCancel :: TVar Bool -> STM x -> IO (Maybe x)
atomicallyWithCancel cancel act = atomically ((readTVar cancel >>= check . not >> return Nothing) `orElse` (Just <$> act))

Note that this still has to have a consistent view of memory to successfully "cancel", but if it reaches the end of the transaction it will notice an inconsistent read of the "cancel" tvar and restart the transaction.  Then it will quickly commit the cancel transaction that only reads a single TVar and returns Nothing.

Ryan

On Sat, Nov 28, 2020 at 4:07 PM amindfv--- via Haskell-Cafe <haskell-cafe@haskell.org> wrote:
I'd like to be able to give up on an STM transaction: roll back and don't retry.
I've cooked up something with exceptions but it feels a bit icky to use exceptions for something like this - is there a better way?:

    data Rollback = Rollback deriving (Show)
    instance Exception Rollback

    rollback :: STM x
    rollback = throwSTM Rollback

    atomicallyWithRollback :: STM x -> IO (Maybe x)
    atomicallyWithRollback a =
       (Just <$> atomically a)
          `catch` (\Rollback -> pure Nothing)

The alternative I've found is something like:

    otherWay :: STM x -> IO (Maybe x)
    otherWay a =
       atomically $ (Just <$> a) `orElse` pure Nothing

But this turns any "retry" in "a" into a rollback, and I'd like to have the option to do either (retry or rollback).

Thanks,
Tom


_______________________________________________
Haskell-Cafe mailing list
To (un)subscribe, modify options or view archives go to:
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Only members subscribed via the mailman list are allowed to post.