D'accord, première règle de gestion des erreurs dans Haskell: ne jamais utilisererror
.
C'est juste terrible à tous points de vue. Il existe purement comme un acte d'histoire et le fait que Prelude l'utilise est terrible. Ne l'utilisez pas.
Le seul moment imaginable que vous pourriez utiliser est quand quelque chose est si terrible en interne que quelque chose doit être incorrect avec le tissu même de la réalité, rendant ainsi le résultat de votre programme théorique.
Maintenant , la question devient Maybe
vs Either
. Maybe
est bien adapté à quelque chose comme head
, qui peut ou non retourner une valeur mais il n'y a qu'une seule raison possible d'échouer. Nothing
dit quelque chose comme "il s'est cassé, et vous savez déjà pourquoi". Certains diraient que cela indique une fonction partielle.
La forme la plus robuste de gestion des erreurs est Either
+ une erreur ADT.
Par exemple, dans l'un de mes compilateurs de loisirs, j'ai quelque chose comme
data CompilerError = ParserError ParserError
| TCError TCError
...
| ImpossibleError String
data ParserError = ParserError (Int, Int) String
data TCError = CouldntUnify Ty Ty
| MissingDefinition Name
| InfiniteType Ty
...
type ErrorM m = ExceptT CompilerError m -- from MTL
Maintenant, je définis un tas de types d'erreur, en les imbriquant de sorte que j'ai une glorieuse erreur de niveau supérieur. Cela peut être une erreur de n'importe quelle étape de la compilation ou un ImpossibleError
, ce qui signifie un bogue du compilateur.
Chacun de ces types d'erreur essaie de conserver le plus d'informations possible le plus longtemps possible pour une jolie impression ou une autre analyse. Plus important encore, en n'ayant pas de chaîne, je peux tester que l'exécution d'un programme de type incorrect via le vérificateur de type génère en fait une erreur d'unification! Une fois que quelque chose est un String
, c'est parti pour toujours et toute information qu'il contient est opaque pour le compilateur / tests, donc ce Either String
n'est pas génial non plus.
Enfin, j'emballe ce type dans ExceptT
un nouveau transformateur monade de MTL. C'est essentiellement EitherT
et est livré avec un joli lot de fonctions pour lancer et attraper des erreurs de manière pure et agréable.
Enfin, il convient de mentionner que Haskell a les mécanismes pour prendre en charge la gestion des exceptions comme le font d'autres langues, sauf que la capture d'une exception existe IO
. Je sais que certaines personnes aiment les utiliser pour IO
des applications lourdes où tout pourrait potentiellement échouer, mais si rarement qu'elles n'aiment pas y penser. Que vous utilisiez ces exceptions impures ou simplement, ExceptT Error IO
c'est vraiment une question de goût. Personnellement, j'opte pour ExceptT
car j'aime qu'on me rappelle les risques d'échec.
En résumé,
Maybe
- Je peux échouer d'une manière évidente
Either CustomType
- Je peux échouer, et je vais te dire ce qui s'est passé
IO
+ exceptions - j'échoue parfois. Consultez mes documents pour voir ce que je jette quand je le fais
error
- Je te déteste aussi, utilisateur
head
oulast
semblent utilisererror
, alors je me demandais si c'était vraiment une bonne façon de faire les choses et il me manquait juste quelque chose. Cela répond à cette question. :)Je ne séparerais pas 2 et 3 en fonction du nombre de façons dont quelque chose peut échouer. Dès que vous pensez qu'il n'y a qu'une seule façon possible, une autre montrera son visage. La métrique devrait plutôt être «mes appelants se soucient-ils de la raison pour laquelle quelque chose a échoué? Peuvent-ils réellement faire quelque chose?».
Au-delà de cela, il n'est pas immédiatement clair pour moi que cela
Either String SomeType
peut produire une condition d'erreur. Je ferais un type de données algébrique simple avec les conditions avec un nom plus descriptif.Ce que vous utilisez dépend de la nature du problème auquel vous êtes confronté et des idiomes du progiciel avec lequel vous travaillez. Bien que j'aurais tendance à éviter le n ° 1.
la source
Either
d'erreurs est un modèle très connu dans Haskell.Either
n'est pas la partie peu claire, l'utilisation deString
comme une erreur plutôt qu'une chaîne réelle.