问题
I am trying to validate a list of strings sequentially and define the validation result type like that:
import cats._, cats.data._, cats.implicits._
case class ValidationError(msg: String)
type ValidationResult[A] = Either[NonEmptyList[ValidationError], A]
type ListValidationResult[A] = ValidationResult[List[A]] // not a monad :(
I would like to make ListValidationResult a monad. Should I implement flatMap and pure manually or there is an easier way ?
回答1:
I suggest you to take a totally different approach leveraging cats Validated:
import cats.data.Validated.{ invalidNel, valid }
val stringList: List[String] = ???
def evaluateString(s: String): ValidatedNel[ValidationError, String] =
if (???) valid(s) else invalidNel(ValidationError(s"invalid $s"))
val validationResult: ListValidationResult[String] =
stringList.map(evaluateString).sequenceU.toEither
It can be adapted for a generic type T, as per your example.
Notes:
val stringList: List[String] = ???is the list of strings you want to validate;ValidatedNel[A,B]is just a type alias forValidated[NonEmptyList[A],B];evaluateStringshould be your evaluation function, it is currently just an unimplemented stubif;sequenceUyou may want to readcatsdocumentation about it: sequenceU;toEitherdoes exactly what you think it does, it converts aValidated[A,B]to anEither[A,B].
As @Michael pointed out, you could also use traverseU instead of map and sequenceU
val validationResult: ListValidationResult[String] =
stringList.traverseU(evaluateString).toEither
来源:https://stackoverflow.com/questions/43211940/how-to-make-it-a-monad