Коли я використовую яку функцію?
Ось рекомендація з документації Control.Exception:
- Якщо ви хочете зробити деякі очищення в тому випадку, якщо виникає виняток, використовувати
finally, bracketабо onException.
- Щоб відновитись після виключення та зробити щось інше, найкращий вибір - скористатися одним із
tryсім’ї.
- ... якщо ви не відновлюєтесь від асинхронного винятку, у цьому випадку використовуйте
catchабо catchJust.
try :: Exception e => IO a -> IO (Або ea)
tryвиконує IOдію для запуску і повертає файл Either. Якщо обчислення вдалося, результат видається обгорнутим у Rightконструктор. (Думайте правильно, а не неправильно). Якщо дія викликала виняток із зазначеного типу , вона повертається у Leftконструкторі. Якщо виняток не був відповідного типу, він продовжує поширюватися вгору по стеку. Вказівка SomeExceptionяк тип охоплює всі винятки, що може бути або не бути гарною ідеєю.
Зверніть увагу, що якщо ви хочете вловити виняток із чистого обчислення, вам доведеться використовувати evaluateдля примусової оцінки в межах try.
main = do
result <- try (evaluate (5 `div` 0)) :: IO (Either SomeException Int)
case result of
Left ex -> putStrLn $ "Caught exception: " ++ show ex
Right val -> putStrLn $ "The answer was: " ++ show val
catch :: Виняток e => IO a -> (e -> IO a) -> IO a
catchє подібним до try. Спочатку він намагається запустити вказану IOдію, але якщо викидається виняток, обробник отримує виняток, щоб отримати альтернативну відповідь.
main = catch (print $ 5 `div` 0) handler
where
handler :: SomeException -> IO ()
handler ex = putStrLn $ "Caught exception: " ++ show ex
Однак є одна важлива відмінність. При використанні catchвашого обробника не можна перервати асинхронний виняток (тобто викинути з іншого потоку через throwTo). Спроби викликати асинхронний виняток будуть блокуватися, поки ваш обробник не закінчить роботу.
Зверніть увагу, що catchв Прелюдії є інше , тому, можливо, ви захочете це зробити import Prelude hiding (catch).
handle :: Виняток e => (e -> IO a) -> IO a -> IO a
handleпросто catchз аргументами в зворотному порядку. Який із них використовувати, залежить від того, що робить ваш код більш читабельним, або який підходить краще, якщо ви хочете використовувати часткове додаток. В іншому випадку вони ідентичні.
tryJust, catchJust і handleJust
Зверніть увагу , що try, catchі handleбуде ловити все виключення із зазначеного / виведеного типу. tryJustі друзі дозволяють вказати функцію селектора, яка відфільтровує, які виключення ви хочете обробити. Наприклад, усі арифметичні помилки мають тип ArithException. Якщо ви хочете лише зловити DivideByZero, ви можете зробити:
main = do
result <- tryJust selectDivByZero (evaluate $ 5 `div` 0)
case result of
Left what -> putStrLn $ "Division by " ++ what
Right val -> putStrLn $ "The answer was: " ++ show val
where
selectDivByZero :: ArithException -> Maybe String
selectDivByZero DivideByZero = Just "zero"
selectDivByZero _ = Nothing
Примітка про чистоту
Зверніть увагу, що цей тип обробки винятків може відбуватися лише в нечистому коді (тобто IOмонаді). Якщо вам потрібно обробляти помилки в чистому коді, вам слід вивчити повернення значень за допомогою Maybeабо Eitherзамість цього (або іншого алгебраїчного типу даних). Це часто переважно, оскільки воно є більш чітким, тому ви завжди знаєте, що де може статися. Monads like Control.Monad.Errorробить цей тип обробки помилок простішим у роботі.
Дивитися також: