可组合的原子类操作

use*_*184 5 haskell transactions atomic

我想编写可能失败的操作,但有一种方法可以回滚.

例如 - 预订酒店房间的外部电话,以及向信用卡收取的外部电话.这两个电话都可能失败,例如没有房间,信用卡无效.两者都有办法回滚 - 取消酒店房间,取消信用卡收费.

  1. 这种(非真实的)原子是否有名称.每当我搜索haskell交易时,我都会得到STM.
  2. 是否有抽象,组合它们的方式,或haskell或任何其他语言的库?

我觉得你可以编写一个monad Atomic T来跟踪这些操作,如果有异常则将它们回滚.

编辑:

这些操作可以是IO操作.如果操作只是内存操作,正如两个答案所示,STM就足够了.

例如,通过HTTP请求预订酒店.数据库操作,例如通过套接字通信插入记录.

在现实世界中,对于不可逆转的操作,在操作完成之前有一段宽限期 - 例如,信用卡付款和酒店预订可以在当天结束时结算,因此在此之前可以取消.

ami*_*dfv 6

这正是STM的目的.组成动作以便它们自动地一起成功或失败.

与您的酒店房间问题非常相似的是Simon Peyton-Jones在"Beautiful Code"中的章节中的银行交易示例:http://research.microsoft.com/en-us/um/people/simonpj/papers/stm/beautiful. PDF格式


dav*_*420 5

如果您需要使用自己的monad,它将看起来像这样:

import Control.Exception (onException, throwIO)

newtype Rollbackable a = Rollbackable (IO (IO (), a))

runRollbackable :: Rollbackable a -> IO a
runRollbackable (Rollbackable m) = fmap snd m
    -- you might want this to catch exceptions and return IO (Either SomeException a) instead

instance Monad Rollbackable where
    return x = Rollbackable $ return (return (), x)
    Rollbackable m >>= f
       = do (rollback, x) <- m
            Rollbackable (f x `onException` rollback)
Run Code Online (Sandbox Code Playgroud)

(你可能也想要FunctorApplicative实例,但它们是微不足道的.)

您将以这种方式定义可回滚的原始操作:

rollbackableChargeCreditCard :: CardNumber -> CurrencyAmount -> Rollbackable CCTransactionRef
rollbackableChargeCreditCard ccno amount = Rollbackable
   $ do ref <- ioChargeCreditCard ccno amount
        return (ioUnchargeCreditCard ref, ref)

ioChargeCreditCard :: CardNumber -> CurrencyAmount -> IO CCTransactionRef
-- use throwIO on failure
ioUnchargeCreditCard :: CCTransactionRef -> IO ()
-- these both just do ordinary i/o
Run Code Online (Sandbox Code Playgroud)

然后像这样运行它们:

runRollbackable
   $ do price <- rollbackableReserveRoom roomRequirements when
        paymentRef <- rollbackableChargeCreditCard ccno price
        -- etc
Run Code Online (Sandbox Code Playgroud)