使用`do notation`进行错误处理?

时间:2015-11-24 15:31:02

标签: haskell error-handling

鉴于数据结构:

data CustomError = FooError | BarError deriving Show

然后执行IO的两个函数:

foo :: IO (Either CustomError Int)
foo = return $ Right 100

bar :: IO (Either CustomError Int)
bar = return $ Left BarError

添加两个Either的方法。

add :: Either CustomError Int -> Either CustomError Int -> Either CustomError Int
add e1 e2 = (+) <$> e1 <*> e2

最后,该函数执行两个IO操作,然后尝试将add应用于其提取的Right值:

f :: IO (Either CustomError Int)
f = do
    x <- foo
    y <- bar
    return $ add x y

运行它显示:

λ: f
Left BarError

但是,假设调用foo将数据持久存储到数据库中。如果foo成功,但bar失败,则会出现不规则状态。换句话说,我希望f像交易一样运作 - 一切都成功或什么都没有。

我想做类似的事情:

fWithRecovery:: IO (Either CustomError Int)
fWithRecovery = do
    x      <- foo
    y      <- bar
    case y of (Right _)       -> return $ add x y
              (Left FooError) -> fmap Right recoverFoo
              (Left BarError) -> fmap Right recoverBar


recoverFoo :: IO Int
recoverFoo = do
    _ <- undefined -- clean up DB
    return 666     -- using an 'evil' value 
                   -- Note - I know using this value is horrible, but
                   --   I'm using for this simple example

recoverBar :: IO Int
recoverBar = do
    _ <- undefined -- clean up DB
    return 42      -- Note - I know using this value is horrible, but
                   --   I'm using for this simple example

但是,我很好奇是否有一种惯用的方式来处理do notation案例的回滚。

0 个答案:

没有答案