Kiedy używać której funkcji?
Oto zalecenie z dokumentacji Control.Exception:
- Jeśli chcesz zrobić porządki w przypadku, gdy jest wyjątek, stosowanie
finally, bracketlubonException .
- Aby odzyskać po wyjątku i zrobić coś innego, najlepszym wyborem jest użycie jednego z plików
try rodziny.
- ... chyba że odzyskujesz z asynchronicznego wyjątku, w takim przypadku użyj
catchlub catchJust.
try :: Exception e => IO a -> IO (albo ea)
trypodejmuje IOakcję do uruchomienia i zwraca plik Either. Jeśli obliczenia się powiodły, wynik jest zawijany w Rightkonstruktorze. (Myśl dobrze, a nie źle). Jeśli akcja rzuciła wyjątek określonego typu , jest on zwracany w Leftkonstruktorze. Jeśli wyjątek nie był odpowiedniego typu, propaguje dalej w górę stosu. Określenie SomeExceptionjako typu spowoduje przechwycenie wszystkich wyjątków, co może być dobrym pomysłem lub nie.
Zauważ, że jeśli chcesz złapać wyjątek z czystego obliczenia, będziesz musiał użyć evaluatedo wymuszenia oceny w 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 :: Exception e => IO a -> (e -> IO a) -> IO a
catchjest podobny do try. Najpierw próbuje uruchomić określoną IOakcję, ale jeśli zostanie zgłoszony wyjątek, program obsługi otrzymuje wyjątek, aby uzyskać alternatywną odpowiedź.
main = catch (print $ 5 `div` 0) handler
where
handler :: SomeException -> IO ()
handler ex = putStrLn $ "Caught exception: " ++ show ex
Jest jednak jedna ważna różnica. Podczas korzystania catchz programu obsługi nie można go przerwać przez wyjątek asynchroniczny (tj. Wyrzucony z innego wątku przez throwTo). Próby wywołania asynchronicznego wyjątku będą blokowane do momentu zakończenia działania programu obsługi.
Zwróć uwagę, że catchw Preludium jest coś innego , więc możesz chcieć to zrobić import Prelude hiding (catch).
handle :: Exception e => (e -> IO a) -> IO a -> IO a
handle jest po prostu catch z argumentami w odwrotnej kolejności. To, którego użyć, zależy od tego, co sprawia, że twój kod jest bardziej czytelny, lub który pasuje lepiej, jeśli chcesz używać częściowej aplikacji. Poza tym są identyczne.
tryJust, catchJust and handleJust
Należy zauważyć, że try, catchi handlezłapie wszystkie wyjątki podanego / wywnioskować typu. tryJusti przyjaciele pozwalają ci określić funkcję selektora, która filtruje wyjątki, które chcesz obsłużyć. Na przykład wszystkie błędy arytmetyczne są typu ArithException. Jeśli chcesz tylko złapać DivideByZero, możesz:
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
Uwaga o czystości
Zauważ, że ten typ obsługi wyjątków może mieć miejsce tylko w przypadku nieczystego kodu (np. IOMonady). Jeśli potrzebujesz obsługiwać błędy w czystym kodzie, powinieneś spojrzeć na zwracanie wartości za pomocą Maybelub Eitherzamiast tego (lub innego algebraicznego typu danych). Jest to często preferowane, ponieważ jest bardziej wyraźne, więc zawsze wiesz, co może się zdarzyć i gdzie. Control.Monad.ErrorTakie monady ułatwiają obsługę tego typu błędów.
Zobacz też: