La gestion des exceptions en Haskell
J'ai besoin d'aide pour comprendre l'utilisation des trois Haskell fonctions
- essayer (
Control.Exception.try :: Exception e => IO a -> IO (Either e a)
) - catch (
Control.Exception.catch :: Exception e => IO a -> (e -> IO a) -> IO a
) - la poignée (
Control.Exception.handle :: Exception e => (e -> IO a) -> IO a -> IO a
)
J'ai besoin de savoir plusieurs choses:
- Quand dois-je utiliser la fonction?
- Comment puis-je utiliser cette fonction avec un simple exemple?
- Où est la différence entre la capture et la poignée? Ils ont presque la même signature qu'avec un ordre différent.
Je vais essayer d'écrire mes essais et j'espère que vous pourrez m'aider:
essayer
J'ai un exemple comme:
x = 5 `div` 0
test = try (print x) :: IO (Either SomeException ())
J'ai deux questions:
-
Comment puis-je personnaliser la sortie d'erreur?
-
Que puis-je faire pour mettre toutes les erreurs à SomeException donc je ne doit écrire le
:: IO (Either SomeException())
catch/essayer
Pouvez-vous me montrer un petit exemple avec un message d'erreur personnalisé de sortie?
Vous devez vous connecter pour publier un commentaire.
Quand dois-je utiliser la fonction?
Voici la recommandation du conseil de Contrôle.La documentation des exceptions:
finally
,bracket
ouonException
.try
famille.catch
oucatchJust
.essayer :: Exception e => IO a -> IO (Soit e un)
try
prend unIO
action à exécuter, et renvoie unEither
. Si le calcul réussi, le résultat est donné enveloppé dans unRight
constructeur. (Pensez à droit, par opposition à tort). Si l'action a déclenché une exception du type spécifié, elle est retournée dans unLeft
constructeur. Si l'exception a été pas du type approprié, il continue à se propager de la pile. La spécification deSomeException
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
evaluate
pour forcer l'évaluation au sein de l'try
.catch :: Exception e => IO a -> e -> IO a) -> IO un
catch
est similaire àtry
. Il tente d'abord d'spécifiéIO
action, mais si une exception est levée, le gestionnaire est donné l'exception d'obtenir une réponse alternative.Cependant, il y a une différence importante. Lors de l'utilisation de
catch
votre gestionnaire ne peut pas être interrompue par une asynchroneous exception (c'est à dire jeté partir d'un autre thread viathrowTo
). Essaie de soulever un asynchroneous exception bloquera jusqu'à ce que votre gestionnaire a fini de s'exécuter.Remarque qu'il existe une autre
catch
dans le Prélude, de sorte que vous pourriez vouloir faireimport Prelude hiding (catch)
.poignée :: Exception e => e -> IO a) -> IO a -> IO un
handle
est tout simplementcatch
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
Noter que
try
,catch
ethandle
va attraper tous 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 typeArithException
. Si vous ne voulez attraperDivideByZero
, vous pouvez le faire:Une remarque sur la pureté
Noter que ce type de gestion d'exception ne peut se faire que dans impur code (c'est à dire la
IO
monade). Si vous avez besoin de gérer les erreurs dans le code pur, vous devez retourner des valeurs à l'aideMaybe
ouEither
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 commeControl.Monad.Error
rend ce type d'erreur de manipulation plus facile de travailler avec.Voir aussi:
try
, sauf si vous êtes en train de récupérer à partir d'un asynchrones exception, auquel cas l'utilisationcatch
"Edward Z. Yang a un article sur la manipulation d'exception en haskell: 8 façons de signaler les erreurs en Haskell revisité.
Re: question 3: attraper et manipuler sont les même (trouvé par le biais de hoogle). Le choix de l'utiliser dépend généralement de la durée de chaque argument. Si l'action est plus courte, l'utilisation de capture et vice versa. Simple poignée exemple à partir de la documentation:
Aussi, vous pouvez, en théorie au curry la poignée de la fonction d'un gestionnaire personnalisé, que vous pouvez ensuite passer autour, par exemple. (adapté à partir de la documentation):
Des messages d'erreur personnalisés:
Je vois qu'une chose aussi vous ennuie (votre deuxième question) est l'écriture de
:: IO (Either SomeException ())
et il m'a ennuyé aussi.J'ai modifié le code maintenant à partir de ce:
À ceci:
Pour ce faire, vous devez utiliser le
ScopedTypeVariables
GHC extension, mais je pense que esthétiquement ça en vaut la peine.