Обработка исключений при выполнении последовательности действий в Haskell - PullRequest
3 голосов
/ 13 сентября 2011

Вот суть кода, в который я собираюсь включить обработку ошибок.

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)

Функции preProcess, initiateJob и makeChart - это то, где мне нужно быть обеспокоенным ошибками. Идея состоит в том, что если какая-либо из этих функций терпеть неудачу, я уменьшаю jCount и вызываю logError. Затем, если jCount > 0, снова запустите те же три функции. Если jCount == 0, продолжайте ждать следующий сигнал.

Каждая из этих функций будет запускать другой процесс, readProcessWithExitCode выглядит так, как я хочу. Затем я буду использовать код выхода для определения успеха или неудачи.

Одна из моих идей заключалась в том, чтобы сделать [preProcess, initiateJob, makeChart]. Тогда я бы отобразил функцию jobProcessor над этим списком. Если один из них функции получили сбой из программы, которую они вызвали, я мог сгенерируйте исключение, и карта перестанет отображать список.

Это разумный подход?

Общие идеи о том, как подойти к этому, и любые вопросы, которые приходят на ум был бы оценен.

Редактировать: В связи с первым заданным вопросом я пересмотрел свое объяснение и отметил, что оно было неполным в важных аспектах. Я думаю заполнены пробелы. Если нет, дайте мне знать.

1 Ответ

1 голос
/ 20 сентября 2011

Давайте просто посмотрим на эту последовательность, оставив пока отсчет.

preProcess world
initiateJob world
makeChart world

В качестве функции верхнего уровня она будет выглядеть как

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

.Мы хотим прервать этот поток выполнения в случае сбоя любого из них и (возможно) перезапустить.

Можно использовать исключения из Haskell или нет.Давайте сначала посмотрим на решение без исключений, потому что оно будет работать и в коде без ввода-вывода.Я не знаю, какие у вас на самом деле типы, так что давайте предположим, что они все

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 перезапускался только сам, я покажу способ сделать это вместо этого.)

...