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
, bracket
oder onException
.
- Um sich nach einer Ausnahme zu erholen und etwas anderes zu tun, ist es am besten, einen
try
Familienmitglied zu verwenden.
- ... es sei denn, Sie erholen sich von einer asynchronen Ausnahme. In diesem Fall verwenden Sie
catch
oder catchJust
.
try :: Exception e => IO a -> IO (entweder ea)
try
führt eine IO
auszuführende Aktion aus und gibt eine zurück Either
. Wenn die Berechnung erfolgreich war, wird das Ergebnis in einen Right
Konstruktor eingeschlossen. (Denken Sie richtig statt falsch). Wenn die Aktion eine Ausnahme des angegebenen Typs auslöste , wird sie in einem Left
Konstruktor zurückgegeben. Wenn die Ausnahme nicht vom entsprechenden Typ war, wird sie den Stapel weiter ausbreiten. Wenn Sie SomeException
als 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 evaluate
Auswertung 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
catch
ist ähnlich wie try
. Zuerst wird versucht, die angegebene IO
Aktion 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 catch
Ihres 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 catch
im 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
handle
ist einfach catch
mit 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
, catch
und handle
wird fangen alle Ausnahmen von der angegebenen / gefolgert Typ. tryJust
Mit 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 IO
Monade) auftreten kann. Wenn Sie Fehler in reinem Code behandeln müssen, sollten Sie prüfen, ob Werte mit Maybe
oder Either
stattdessen (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.Error
erleichtern die Arbeit mit dieser Art der Fehlerbehandlung.
Siehe auch: