5 votes

Scalaz a-t-il quelque chose à accumuler dans l'erreur et le succès ?

J'ai commencé à utiliser Scalaz 7 Validation et/ou disjonction pour traiter une liste d'opérations susceptibles d'échouer et gérer leur résultat.

Il existe deux cas bien documentés pour ce type d'utilisation :

1/ Vous voulez vérifier une liste de conditions sur quelque chose, et accumuler chaque erreur, le cas échéant. Ici, on va toujours à la fin de la liste, et en cas d'erreur, on a un échec comme résultat global. Et c'est un foncteur applicatif au travail.

2/ Vous voulez exécuter plusieurs étapes qui peuvent échouer, et vous arrêter à la première qui échoue. Ici, nous avons une monade qui se marie bien avec la for-comprehension de Scala.

Donc, j'ai deux autres cas d'utilisation qui sont parmi les mêmes lignes, mais qui ne semblent pas bien marcher sur un cas précédent : Je veux traiter une liste d'étapes, avec possibilité d'échec, et accumuler les résultats des erreurs et des succès (ex : c'est une liste de modifications de fichiers, les erreurs peuvent se produire parce que c'est le monde extérieur, et les succès sont des patchs que je veux garder pour plus tard).

La différence entre les deux cas d'utilisation réside uniquement dans le fait que je veux m'arrêter tôt (à la première erreur) ou aller à la fin de la liste.

OK, alors quelle est la bonne chose à faire pour cela ?

(écrire la question m'amène à penser qu'il s'agit d'un simple foldLeft, n'est-ce pas ? Je vais laisser la question ici pour valider, et si quelqu'un d'autre se pose la question)

5voto

mpilquist Points 2410

Jetez un coup d'œil à Validation#append ou son alias Validation#+|+ . Étant donné deux validations, si les deux sont réussies, il renvoie la réussite des valeurs ajoutées. Si les deux validations sont des échecs, il renvoie l'échec des valeurs ajoutées. Sinon, il renvoie la valeur réussie. Cela nécessite une instance implicite de Semigroup pour le type de succès.

4voto

folone Points 4523

Je ferais quelque chose comme ça :

scala> List(1.success[String], 2.success[String], "3".failure[Int], "4".failure[Int]).partition(_.isSuccess)
res2: (List[scalaz.Validation[java.lang.String,Int]], List[scalaz.Validation[java.lang.String,Int]]) = (List(Success(1), Success(2)),List(Failure(3), Failure(4)))

scala> val fun = (_:List[Validation[String, Int]]).reduceLeft(_ append _)
fun: List[scalaz.Validation[String,Int]] => scalaz.Validation[String,Int] = <function1>

scala> fun <-: res2 :-> fun
res3: (scalaz.Validation[String,Int], scalaz.Validation[String,Int]) = (Success(3),Failure(34))

UPD : Avec #129 et #130 fusionnés, vous pouvez changer fun a (_:List[Validation[String, Int]]).concatenate o (_:List[Validation[String, Int]]).suml

Ou bimap comme ça :

scala> List(1.success[String], 2.success[String], "3".failure[Int], "4".failure[Int]).partition(_.isSuccess).bimap(_.suml, _.suml)
res6: (scalaz.Validation[java.lang.String,Int], scalaz.Validation[java.lang.String,Int]) = (Success(3),Failure(34))

1voto

ron Points 4636

Ce dont vous avez besoin, c'est d'une commutation approximative d'un Either[E, A] en un Writer[List[E], A] . Le site Writer enregistre les erreurs que vous avez rencontrées.

0voto

Jens Schauder Points 23468

On dirait que vous voulez une paire (SomveValue, List[T]) donde T est votre "échec", bien que je l'appellerais "avertissement" ou "journal" puisque vous obtenez quand même un résultat, donc ce n'est pas vraiment un échec.

Je ne sais pas si Scalaz a quelque chose de spécial pour ça.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X