Wann benutze ich welche Funktion?
Hier ist die Empfehlung aus der Control.Exception-Dokumentation:
- Wenn Sie einige Bereinigung in dem Fall tun mögen , dass eine Ausnahme ausgelöst wird, verwenden
finally, bracketoder onException.
- Um sich nach einer Ausnahme zu erholen und etwas anderes zu tun, ist es am besten, einen
tryFamilienmitglied zu verwenden.
- ... es sei denn, Sie erholen sich von einer asynchronen Ausnahme. In diesem Fall verwenden Sie
catchoder catchJust.
try :: Exception e => IO a -> IO (entweder ea)
tryführt eine IOauszuführende Aktion aus und gibt eine zurück Either. Wenn die Berechnung erfolgreich war, wird das Ergebnis in einen RightKonstruktor eingeschlossen. (Denken Sie richtig statt falsch). Wenn die Aktion eine Ausnahme des angegebenen Typs auslöste , wird sie in einem LeftKonstruktor zurückgegeben. Wenn die Ausnahme nicht vom entsprechenden Typ war, wird sie den Stapel weiter ausbreiten. Wenn Sie SomeExceptionals Typ angeben, werden alle Ausnahmen abgefangen , die möglicherweise eine gute Idee sind oder nicht.
Beachten Sie, dass Sie, wenn Sie eine Ausnahme von einer reinen Berechnung abfangen möchten, die evaluateAuswertung innerhalb der erzwingen müssen 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
catchist ähnlich wie try. Zuerst wird versucht, die angegebene IOAktion auszuführen. Wenn jedoch eine Ausnahme ausgelöst wird, erhält der Handler die Ausnahme, um eine alternative Antwort zu erhalten.
main = catch (print $ 5 `div` 0) handler
where
handler :: SomeException -> IO ()
handler ex = putStrLn $ "Caught exception: " ++ show ex
Es gibt jedoch einen wichtigen Unterschied. Bei Verwendung catchIhres Handlers kann nicht durch eine asynchrone Ausnahme unterbrochen werden (dh von einem anderen Thread über ausgelöst throwTo). Versuche, eine asynchrone Ausnahme auszulösen, werden blockiert, bis Ihr Handler die Ausführung beendet hat.
Beachten Sie, dass es catchim Prelude einen anderen gibt , also möchten Sie vielleicht etwas tun import Prelude hiding (catch).
handle :: Exception e => (e -> IO a) -> IO a -> IO a
handleist einfach catchmit den Argumenten in umgekehrter Reihenfolge. Welche verwendet werden soll, hängt davon ab, was Ihren Code lesbarer macht oder welche besser passt, wenn Sie eine Teilanwendung verwenden möchten. Sie sind ansonsten identisch.
tryJust, catchJust und handleJust
Beachten Sie, dass try, catchund handlewird fangen alle Ausnahmen von der angegebenen / gefolgert Typ. tryJustMit und Freunden können Sie eine Auswahlfunktion angeben, die herausfiltert, welche Ausnahmen Sie speziell behandeln möchten. Beispielsweise sind alle arithmetischen Fehler vom Typ ArithException. Wenn Sie nur fangen wollen DivideByZero, können Sie:
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
Ein Hinweis zur Reinheit
Beachten Sie, dass diese Art der Ausnahmebehandlung nur in unreinem Code (dh der IOMonade) auftreten kann. Wenn Sie Fehler in reinem Code behandeln müssen, sollten Sie prüfen, ob Werte mit Maybeoder Eitherstattdessen (oder einem anderen algebraischen Datentyp) zurückgegeben werden. Dies ist oft vorzuziehen, da es expliziter ist, sodass Sie immer wissen, was wo passieren kann. Monaden wie Control.Monad.Errorerleichtern die Arbeit mit dieser Art der Fehlerbehandlung.
Siehe auch: