我有一个非常简单的抽象来处理可以回滚(在某种程度上)的IO动作序列,即如果动作写入文件,则回滚将删除此文件或动作创建一个目录树,修剪它会回滚等回滚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](http://hackage.haskell.org/package/resourcet-1.1.7.3/docs/Control-Monad-Trans-Resource.html):“修改过的ReaderT monad转换器保持对仍然要执行的所有发布操作的可变引用“。区别在于清理操作只能在出现错误时执行。鉴于'ResourceT'为用户提供了对其[内部状态]的访问权限(http://hackage.haskell.org/package/resourcet-1.1.7.3/docs/Control-Monad-Trans-Resource.html#g:9)也许它可以作为“RollbackT”实现的基础。 – danidiaz