Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Converting a list of either to a cats ValidatedNel

Given:

def convert[T](list: List[Either[String, T]]): Validated[NonEmptyList[String], NonEmptyList[T]] =
  NonEmptyList.fromList(list)
    .toRight("list is empty")
    .flatMap(...

How do I flat map the NonEmptyList[Either[String, T]] so ultimately I end up with my Validated return value?

Is there anything in the cats library to account for this scenario? Or do I need to do this manually following something like: Best way to turn a Lists of Eithers into an Either of Lists?

like image 397
Cheetah Avatar asked Jan 18 '18 12:01

Cheetah


1 Answers

I'd write this as follows:

import cats.data.{ NonEmptyList, Validated, ValidatedNel }
import cats.instances.list._, cats.syntax.list._
import cats.syntax.either._
import cats.syntax.option._
import cats.syntax.traverse._

def convert[T](list: List[Either[String, T]]): ValidatedNel[String, NonEmptyList[T]] =
  list.traverse(_.toValidatedNel).andThen(_.toNel.toValidNel("list is empty"))

First we flip the whole thing inside out while transforming the Eithers to Validateds (with traverse and toValidatedNel), to get a ValidatedNel[String, List[T]], and then we handle the case where the result is empty (with andThen and toNel).

The andThen is probably one of the pieces you're missing—it's essentially flatMap for Validated (but without the implications and syntactic sugar baggage that flatMap brings). If you wanted you could probably pretty easily change my version to do the empty list check first, as in your sketch, but the way I've written it feels a little more natural to me.

Footnote: I have no idea why the enrichment method for Option is named toValidNel while the one for Either is toValidatedNel—I hadn't noticed this before, probably because I hadn't used them in the same line before. This seems unfortunate, especially since we're stuck with it for a while now that Cats 1.0 is out.

Another footnote: note that you'll need the -Ypartial-unification compiler option enabled for traverse to work without type parameters if you're on 2.11.

like image 130
Travis Brown Avatar answered Nov 04 '22 04:11

Travis Brown