【发布时间】:2016-09-27 09:28:44
【问题描述】:
我有一个非常简单的抽象来处理可以回滚(在某种程度上)的一系列 IO 操作,即如果一个操作写入一个文件,那么回滚将删除这个文件或者如果一个操作创建一个目录树,修剪它会是回滚等。
data IOAction = IOAction {
execute :: IO (),
rollback :: IO ()
}
executeAll :: [IOAction] -> IO ()
executeAll [] = return ()
executeAll (a : as) = do
execute a
executeAll as `catch` rollbackAndRethrow
where
rollbackAndRethrow :: SomeException -> IO ()
rollbackAndRethrow e = rollback a >> throw e
它几乎可以满足我的需求,但我有一种强烈的预感,那就是有更多可组合和更可靠(在异常处理的意义上)的方法来做到这一点。所以我的问题是,我可以使用某个库中已知的 monad 转换器来实现相同的想法吗?
有类似的东西
writeFilesAtomically :: CanRollbackT IO ()
writeFilesAtomically = do
a1 <- (writeFile a str1) `orRollback` removeFile a
a2 <- (writeFile x str2) `orRollback` removeFile x
....
会比目前的解决方案更方便。
【问题讨论】:
-
像这样的 monad 看起来类似于 ResourceT:“一个修改后的 ReaderT monad 转换器,持有对所有仍待执行的释放操作的可变引用”。不同之处在于,只有在出现错误的情况下才会执行清理操作。鉴于
ResourceT允许用户访问其internal state,也许它可以作为RollbackT实现的基础。