J'ai une fonction HASKELLL qui prend une entrée utilisateur et une autre fonction qui valide cette entrée. Bien sûr, la validation pourrait échouer, auquel cas je voudrais renvoyer un message d'erreur donnant des commentaires sur ce qui a été mal fait. P>
Je sais qu'il y a plusieurs façons que je puisse faire cela. Après la petite expérience que j'ai, il semble que le meilleur moyen soit d'utiliser soit une chaîne A code>. Ce qui me jette, c'est que je me fiche du
a code>. Soit il échoue et j'aimerais stocker plus d'informations ou réussir. Le
A code> est gaspillé. P>
peut-être chaîne code> un moyen acceptable de stocker un message d'erreur? strong> Ça me sent en arrière, mais ignore complètement la valeur à droite d'un
code> est assez mauvais aussi. Qu'est-ce qui est Canonical ici? P>
5 Réponses :
Qu'est-ce qu'un message d'erreur et une valeur attendue n'est qu'une question de point de vue. Si vous ne vous souciez pas de la valeur de résultat code> code>, mais faites attention à un message d'erreur possible, ce message est, aussi loin que vous êtes concerné, la valeur d'intérêt. Donc, assurez-vous que vous pouvez le stocker comme un En fait, il est peu différent avec Si vous aviez un Pour préciser les types que vous parlez de messages d'erreur, je n'utiliserais aucun peut-être chaîne code>. P>
soit code>. Ce que je trouve en arrière, c'est que
soit code> est généralement perçu comme "le type d'échec possible". Oui, son instance monad arrive à fonctionner dans la manière qui fait
gauche code> error-ish et
droite code> succès-ish, mais ab initio
code> est juste Un simple bifoncteur exprimant la somme de deux types. En effet, si Haskell avait toujours eu des opérateurs de type,
soit A B code> serait probablement écrit
A + B code> ou
A || b code>. p>
String a code> et souhaitez "confisquer" la valeur possible
A code>, le moyen le plus simple est de simplement
fmap (const ()) code> sur elle, entraînant un
String () code>, qui est isomorphe à
peut-être chaîne code> mais "ressemble plus à la chaîne code> a Caractère d'erreur ", bien que j'ai dit que ceci est un peu stupide. p>
ni code> ni
peut-être code> mais
sauf chaîne () code> a>. Souvent, les valeurs d'erreur sont prises sur une autre monad quand même, vous auriez donc par exemple.
sauf String io () code>. p>
Je suggérerais d'utiliser un type personnalisé, isomorphe à ou même p> peut-être chaîne code>.
peut-être code>, car nous pouvons exploiter
GénéraliséNewTypeDeriving code>
Pour obtenir le même effet P> foo :: Result -> ...
foo (Error x) = ...
foo OK = ...
Avec peut-être code>, les validateurs peuvent être chine trivialement avec
<|> code>; Avec ce type personnalisé, ce n'est pas le cas.
Je viens d'apprendre à propos d'une nouvelle classe de type, merci d'avoir apporté la note sur <|> code>. Serait-il raisonnable de générer une instance d'alternative pour obtenir ce comportement? Ou est-ce le genre de chose où si je le mettez moi-même, je le fais probablement mal?
@jcolemang Oui, ce serait raisonnable. Il est un peu malheureux d'avoir à dupliquer le code déjà présent. Je vais mettre à jour avec une autre alternative.
Combinant des validateurs avec <|> code> est un exemple parfait de pourquoi vous devriez définir un nouveau type
ok | Erreur A CODE>, sauf si vous souhaitez penser à un validateur "succédant" quand il "réussit" trouve quelque chose d'invalide sur l'entrée.
@Reidbarton Si vous avez considéré un validateur réussissant quand il n'a pas trouvé quelque chose d'invalide, n'utiliserais pas <|> code> résultat dans un résultat valide si seulement des validateurs ont échoué? Ou suis-je mal compris?
Le point est toute la prémisse d'utiliser <|> code> pour les validateurs de chaîne (en supposant que cela signifie que vous souhaitez vérifier si elles acceptent l'entrée comme valide) est en cours et déroutant, car
a <| > B code> consiste à réussir lorsque
a code> ou
B code> fait. D'où l'alternative du nom. La bonne façon de chaîaliser les validateurs est avec
>> code> (ou quel que soit le nom branché de cet opérateur, est de nos jours). Cela fonctionne par exemple avec
String () code>.
Ce type ne peut pas être un code> Foncteur code>, alternatif code>,
applicatif code> ou
monad code>, comme il a le mauvais type, alors Votre exemple avec GND est incorrect. Ce n'est pas si mauvais, cependant, puisque les cas n'auraient pas vraiment de sens - étant donné que
Error Code> Si le court-circuit, il n'y aurait aucun endroit pour contenir la valeur "Success" et aucun de l'habitude. les typlasses seraient utiles.
@Alexisking Oh, non! Merci. Maintenant, je ne crois plus que la deuxième approche est utile.
oui, mais il y a une abstraction "de validation" plus appropriée "qui vaudrait la peine Explorer, ce qui vous permet de chaîner des validations et d'accumuler des erreurs (c'est-à-dire sans court-circuiter sur la première erreur). Certaines saveurs de mise en œuvre sont dans le peut-être string code> est correct (sa forme de forme précisément sur la plage de votre fonction), mais elle ne compose pas bien car toutes les instances utiles prennent la sémantique opposée pour
peut-être code>.
String () code> serait plus utile (en termes de monad / instances applicatives) et serait également plus clair.
validation code> package
. Du Docs: P> >>> _Success # (+1) <*> _Success # 7 :: AccValidation String Int
AccSuccess 8
>>> _Failure # ["f1"] <*> _Success # 7 :: AccValidation [String] Int
AccFailure ["f1"]
>>> _Success # (+1) <*> _Failure # ["f2"] :: AccValidation [String] Int
AccFailure ["f2"]
>>> _Failure # ["f1"] <*> _Failure # ["f2"] :: AccValidation [String] Int
AccFailure ["f1","f2"]
J'encourage l'utilisation de Continuer la partie "Ajuster ensemble", vous pouvez ensuite constater que vous souhaitez construire un grand validateur en plus petits. Vous avez peut-être un validateur qui vérifie qu'une personne a spécifié une date d'âge et de naissance valide et souhaitez créer un validateur en dehors de cela qui vérifie également que l'âge est à peu près bien à la date de naissance. L'instance sauf chaîne () code> (ou
String () code>) sur
peut-être chaîne code>, pour quelques raisons:
String -> Sauf Chaîne (int, int, int) code> ou similaire. Faire des validateurs qui ne retournent rien d'intéressant ont le type
FOO -> Sauf String () Code> Les fait juste un cas particulier de ce motif - et donc plus facile à adapter ensemble. Li>
monad code> pour
soit code> aidera ici; Par exemple: p>
validatePerson p now = do
age <- validateAge p
date <- validateBirthdate p
validateMatchingAgeAndDate age date now
Après avoir utilisé Haskell pendant quelques mois, je voudrais dire que je suis très fortement d'accord pour dire que c'est la voie à suivre.
N'a-t-il pas d'utilisateur de chaîne code> être une meilleure option?
@ MB14 Qu'est-ce que utilisateur code>, et pourquoi pensez-vous que ce serait une meilleure option que
() code>?
J'ai raté et pensé que l'OP voulait valider un utilisateur ainsi une fonction validateuser :: Utilisateur -> Error string utilisateur code>. Est l'avantage d'être à la chaîne. Cependant, cela n'applique pas la fonction de validation pour ne pas modifier l'entrée.
je voulais la fonctionnalité exacte du ceci permet la fonctionnalité complète de L'inconvénient est que ces deux fonctions fonctionnent toujours: p>
peut-être code>, mais je voulais toujours éviter de retourner
rien code> pour indiquer le succès et le code> juste msg code> pour indiquer échec. Pour contourner cela, j'ai créé ce que sont vraiment des alias vers
peut-être code> mais le vérificateur de type affichera toujours
maybefailure code> si vos types sont incorrects et que vous ne voyez pas
peut-être chaîne code> dans la signature de type, ce qui serait trompeur. < / p>
On dirait que le code que vous écrivez comprend des anticiperns (dans ce cas, éventuellement du code côté effecteur). Vous devriez généralement vous soucier de i> valeur d'un
code> code> (pas de jeu de mots ou de confusion) - c'est-à-dire que dans les deux
gauche code> et
droit code> doit être traité de manière appropriée.
@Jules, je suis d'accord que je devrais m'occuper de chaque côté du
soit code>, c'est pourquoi je pensais que l'utilisation de
peut-être code> était la voie à suivre. Dites-vous que l'utilisateur de l'utilisateur est l'anticitatoire?
Sémantiquement votre fonction de validation peut renvoyer un message d'erreur ou renvoyer un message d'erreur, il semble donc tout à fait raisonnable d'utiliser
peut-être code> pour son type de retour. Ce n'est pas le modèle "Message d'erreur" VS "Ressort correct" que
soit code> implique généralement.