Как написать функцию "retryForever" в Haskell, используя обработку исключений?

Я хотел бы создать функцию, которая может восстанавливаться после любого количества ошибок, и повторить попытку. Конечно, осмысленная обработка ошибок рассматривается в других частях программы - это последняя попытка сохранить работоспособность. Итак, я написал это:

retryForever prog = catchAny prog progRetry
  where
    progRetry :: SomeException -> m a
    progRetry ex = do
      putStrLn $ pack $ show ex
      threadDelay 4000
      prog

Затем я заверну свое основное действие ввода-вывода в retryForever:

main :: IO ()
main = retryForever $ do
  logger <- newLogger
  -- ...

В другой части моей программы (вероятно, в другой зеленой ветке) я проверяю это следующим образом:

error "this is a TEST ERROR"

В результате чего:

: this is a TEST ERROR
CallStack (from HasCallStack):
  error, called at XXXX

(и программа умирает вместо продолжения)

Обратите внимание, что я использую classy-prelude, для случаев, когда это может иметь значение, например catchAny там не обрабатываются асинхронные исключения, что может быть проблемой здесь.

1 ответ

Решение

Когда программа не удалась, вы должны запустить программу prog еще раз, но завернутый в retryForever таким образом, что если он снова потерпит неудачу, вы продолжаете пытаться:

import Control.Monad.Catch(catchAll)

retryForever :: IO a -> IO a
retryForever prog = catchAll prog retry
  where retry ex = do
      putStrLn $ pack $ show ex
      threadDelay 4000
      retryForever prog
Другие вопросы по тегам