Quand dois-je utiliser la fonction?
Voici la recommandation du conseil de Contrôle.La documentation des exceptions:
- Si vous voulez faire un peu de nettoyage dans le cas où une exception est soulevée, utiliser
finally
, bracket
ou onException
.
- Pour récupérer après une exception et de faire autre chose, le meilleur choix est d'utiliser l'un de l'
try
de la famille.
- ... à moins que vous récupérez à partir asynchrone exception, dans quel cas utiliser
catch
ou catchJust
.
essayez :: Exception e => IO a -> IO (e)
try
prend un IO
action à exécuter, et renvoie un Either
. Si le calcul réussi, le résultat est donné enveloppé dans un Right
constructeur. (Pensez à droit, par opposition à tort). Si l'action a déclenché une exception du type spécifié, il est renvoyé en Left
constructeur. Si l'exception n'était pas du type approprié, il continue à se propager de la pile. La spécification SomeException
que le type va attraper toutes les exceptions, qui peut ou peut ne pas être une bonne idée.
Notez que si vous voulez attraper une exception à partir d'un pur calcul, vous devrez utiliser l' evaluate
de la force de l'évaluation au sein de l' 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 un
catch
est similaire à l' try
. Il tente d'abord d'spécifiés IO
d'action, mais si une exception est levée, le gestionnaire est donné l'exception d'obtenir une réponse alternative.
main = catch (print $ 5 `div` 0) handler
where
handler :: SomeException -> IO ()
handler ex = putStrLn $ "Caught exception: " ++ show ex
Cependant, il existe une différence importante. Lors de l'utilisation d' catch
votre gestionnaire ne peut pas être interrompue par une asynchroneous exception (c'est à dire jeté partir d'un autre thread via throwTo
). Essaie de soulever un asynchroneous exception bloquera jusqu'à ce que votre gestionnaire a fini de s'exécuter.
Notez qu'il y a un autre catch
dans le Prélude, de sorte que vous pourriez vouloir faire import Prelude hiding (catch)
.
poignée :: Exception e = > e -> IO a) -> IO a -> IO un
handle
est tout simplement catch
avec les arguments dans l'ordre inverse. À utiliser dépend de ce qui rend votre code plus lisible, ou celui qui correspond le mieux si vous voulez utiliser l'application partielle. Ils sont par ailleurs identiques.
tryJust, catchJust et handleJust
Notez que try
, catch
et handle
va attraper toutes les exceptions de l'/type inféré. tryJust
et amis vous permettent de spécifier un sélecteur de fonction qui filtre des exceptions que vous souhaitez gérer. Par exemple, toutes les erreurs de calcul sont de type ArithException
. Si vous ne voulez attraper DivideByZero
, vous pouvez le faire:
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
Une note sur la pureté
Notez que ce type de gestion d'exception ne peut se faire que dans impur code (c'est à dire l' IO
monade). Si vous avez besoin de gérer les erreurs dans le code pur, vous devez retourner les valeurs à l'aide de Maybe
ou Either
au lieu (ou tout autre type de données algébrique). C'est souvent préférable car il est plus explicite, de sorte que vous savez toujours ce qui peut arriver où. Les monades comme Control.Monad.Error
rend ce type d'erreur de manipulation plus facile de travailler avec.
Voir aussi: