在Haskell中执行一系列操作时的异常处理

时间:2011-09-12 23:52:09

标签: haskell exception-handling monads

以下是我希望将错误处理纳入其中的代码的要点。

worldHandler :: ProcessState -> JobCount -> IO ()
worldHandler world jCount = do
   putStrLn "Entered worldHandler"
   jcount <- takeMVar jCount
   if jcount > 0
      then incrementThenDone jcount
      else doJobProcessing jcount
      where incrementThenDone jcount = do
                putMVar jCount (jcount+1)


            doJobProcessing jcount = do
                putMVar jCount (jcount+1)
                preProcess world
                initiateJob world
                makeChart world

这是main

main :: IO ()
main = do
    world <- (newEmptyMVar :: IO ProcessState)
    jCount <- (newMVar 0 :: IO JobCount)
    installHandler userDefinedSignal1 (Catch $ worldHandler world jCount) Nothing
    forever (threadDelay 10000)

功能preProcessinitiateJobmakeChart是我需要的地方 关心错误。这个想法是,如果任何这些功能 失败,我递减jCount并致电logError。然后,如果jCount > 0,再次启动相同的三个函数。如果jCount == 0,继续等待 下一个信号。

这些功能中的每一个都将开始另一个过程, readProcessWithExitCode看起来像我想要的。然后我会用 退出代码以确定成功或失败。

我的一个想法是制作一个[preProcess, initiateJob, makeChart]。 然后我将函数jobProcessor映射到此列表。如果其中之一 功能从他们调用的程序中收到了失败,我可以 生成一个execption,map将停止在列表上的映射。

这是一个合理的方法吗?

关于如何处理此问题的一般想法,以及任何问题 我会很感激。

编辑:由于提出了第一个问题,我重新评估了我的解释,并指出它在重要方面不完整。我认为填补了空白。如果没有,请告诉我。

1 个答案:

答案 0 :(得分:1)

让我们看看这个序列,暂时搁置计数。

preProcess world
initiateJob world
makeChart world

作为顶级功能,它看起来像

doJobProcessing :: ProcessState -> IO ()
doJobProcessing world = do
    preProcess world
    initiateJob world
    makeChart world

。如果其中任何一个失败,并且(可能)重新启动,我们希望中断该执行流程。

可以使用Haskell异常,也可以不使用。让我们首先看一个没有异常的解决方案,因为它也适用于非IO代码。我不知道你的类型究竟是什么,所以让我们假设它们都是

preProcess, initiateJob, makeChart :: ProcessState -> IO ExitCode

现在这里有一个非常丑陋明显的方法(总是一个好的开始)

doJobProcessing :: ProcessState -> IO ()
doJobProcessing world = do
    preProcessStatus <- preProcess world
    if preProcessStatus /= ExitSuccess
      then jobFail world
      else do
        initiateJobStatus <- initiateJob world
        if initiateJobStatus /= ExitSuccess
          then jobFail world
          else do
            makeChartStatus <- makeChart world
            if makeChartStatus /= ExitSuccess
              then jobFail world
              else return ()  ---success!!!

jobFail :: ProcessState -> IO ()
jobFail world = do
    --some test involving jCount
    if --test says to try again
      then do
        --inc/dec jCount
        doJobProcessing world
      else do
        -- nothing; we give up
        return ()

这表现得怎么样? (如果即使makeChart失败,也会从preProcess开始再次尝试。)如果确实如此,那么我将展示如何使用纯Haskell抽象和/或异常简化它。 (如果你想要preProcess,initiateJob和makeChart中的每一个只重新启动它,我将展示一种方法来代替它。)