En Haskell, je serais emballage ce code dans une combinaison de monades, en utilisant Peut-être la et la et la traduction et de la propagation des erreurs que nécessaire. En fin de compte, tout cela est d'une IO monade où je suis en mesure d'afficher le statut de l'utilisateur.
Dans une autre langue, il me suffit de lever une exception et les attraper dans l'endroit approprié. Simple. Je ne passe pas beaucoup de temps cognitive dans les limbes d'essayer de démêler quelle combinaison de mécanismes dont j'ai besoin.
Je ne dirais pas que vous êtes nécessairement approche de ce mal. Plutôt, votre erreur est de penser que ces deux scénarios sont différents; ils ne sont pas.
De "il suffit de lancer et à attraper" est équivalent à imposer à l'ensemble de votre programme exactement la même structure conceptuelle comme une combinaison de Haskell méthodes de gestion d'erreurs. La combinaison exacte dépend de l'erreur des systèmes de gestion de la langue que vous êtes en la comparant à, qui souligne pourquoi Haskell semble plus compliqué: Il vous permet de mélanger et assortir erreur de manipulation de structures fondées sur le besoin, plutôt que de vous donner un implicite, one-size-fits-plus solution.
Donc, si vous avez besoin d'un style particulier de la gestion d'erreur, vous l'utilisez; et que vous l'utilisez uniquement pour le code qui en a besoin. Code qui n'en a pas besoin, pour des raisons de ni génération, ni de la manipulation de la pertinente sortes d'erreurs--est marqué comme tel, ce qui signifie que vous pouvez utiliser ce code sans se soucier de ce genre d'erreur en cours de création.
Sur le sujet syntaxique de la maladresse, c'est une drôle d'objet. En théorie, il devrait être indolore, mais:
- Haskell a été dictée par la recherche de la langue pendant un certain temps, et, à ses débuts, beaucoup de choses étaient encore en pleine évolution et utile idiomes n'avait pas été popularisés encore, si vieux code flottant autour est susceptible d'être un mauvais modèle
- Certaines bibliothèques ne sont pas aussi souples qu'ils pourraient l'être dans la façon dont les erreurs sont traitées, soit en raison de fossilisation de l'ancien code comme ci-dessus, ou tout simplement manque de polonais
- Je ne suis pas au courant de tout les guides sur la meilleure façon de structure du nouveau code de gestion d'erreur, de sorte que les nouveaux arrivants sont laissés à leur propre sort
Je pense que les chances sont que vous êtes "faire le mal" en quelque sorte, et pourrait éviter la plupart de ce désordre syntaxique, mais que ce n'est probablement pas raisonnable de s'attendre à ce que vous (ou la moyenne des Haskell programmeur) pour trouver les meilleures approches sur leur propre.
Aussi loin que monade transformateur piles aller, je pense que l'approche standard est-à - newtype
de l'ensemble de la pile pour votre application, et d'en tirer ou de mettre en œuvre des instances pour les classes de type (par exemple, MonadError
), puis utilisez le type de la classe des fonctions qui ne sont pas généralement besoin d' lift
ing. Monadique fonctions que vous écrivez pour le cœur de votre application doivent utiliser le newtype
d pile, afin de ne pas avoir besoin de levage, soit. À propos de la seule basse-sémantique-sens chose que vous ne pouvez pas éviter est - liftIO
, je pense.
Traiter avec de grandes piles de transformateurs peuvent être des maux de tête, mais seulement lorsqu'il y a beaucoup de calques imbriqués des différents transformateurs (empiler des couches alternées de StateT
et ErrorT
avec un ContT
jeté dans le milieu, puis juste essayer de me dire ce que votre code sera effectivement le faire). C'est rarement ce que vous voulez vraiment, bien.
Edit: en tant Que mineur, addendum, je veux attirer l'attention sur une remarque plus générale qui m'est apparu lors de l'écriture de quelques commentaires.
Comme je l'ai dit et @sclv démontré joliment, de corriger les erreurs de manipulation vraiment est si compliqué que ça. Tout ce que vous pouvez faire est de l'aléatoire que la complexité autour de, pas à l'éliminer, parce que peu importe ce que vous êtes la réalisation de plusieurs opérations qui peuvent produire des erreurs de façon indépendante et que votre programme doit gérer toutes les combinaisons possibles de toute façon, même si cette "manipulation" est tout simplement de tomber et mourir.
Cela dit, Haskell vraiment ne diffèrent intrinsèque de la plupart des langues sur un point: de manière générale, de gestion des erreurs est à la fois explicite et premier de la classe, ce qui signifie que tout est à l'air libre et peut être manipulé librement. Le revers de la médaille c'est une perte de implicite de gestion des erreurs, ce qui signifie que même si tout ce que vous voulez, c'est pour imprimer un message d'erreur et meurent, vous devez le faire explicitement. Donc, en fait, faire d'erreur de manipulation est plus facile en Haskell, en raison de la première classe des abstractions, mais en ignorant les erreurs est plus difficile. Cependant, ce genre de "toutes les mains abandonner le navire" erreur non la manipulation est presque jamais correct dans toute sorte de monde réel, la production, l'utilisation, c'est pourquoi il semble que la maladresse obtient écarté.
Ainsi, même s'il est vrai que les choses sont plus compliquées au premier abord, lorsque vous avez besoin de traiter avec des erreurs explicitement, la chose importante est de se rappeler que c'est tout là est à lui. Une fois que vous apprendre à utiliser la bonne gestion des erreurs d'abstractions, de la complexité assez bien atteint un plateau et n'a pas vraiment d'obtenir beaucoup plus difficile qu'un programme s'étend; et plus vous l'utilisez ces abstractions les plus naturelles qu'ils deviennent.