(ある程度) ロールバックできる一連の 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
それは私が望んでいることのほとんどを行いますが、それを行うには、より構成可能で信頼性の高い (例外処理の意味で) 方法があるという強い予感があります。私の質問は、たとえば、ライブラリの既知のモナド変換子を使用して、同じアイデアを実装できますか?
のようなものを持つ
writeFilesAtomically :: CanRollbackT IO ()
writeFilesAtomically = do
a1 <- (writeFile a str1) `orRollback` removeFile a
a2 <- (writeFile x str2) `orRollback` removeFile x
....
現在のソリューションよりも便利です。