如何使它成为一个单子?

How to make it a monad?

我正在尝试按顺序验证字符串列表并定义验证结果类型:

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 :(

我想使 ListValidationResult 成为 monad。我应该手动实施 flatMappure 还是有更简单的方法?

我建议您采用完全不同的方法利用 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

根据您的示例,它可以适用于通用类型 T


备注:

  • val stringList: List[String] = ??? 是要验证的字符串列表;
  • ValidatedNel[A,B] 只是 Validated[NonEmptyList[A],B] 的类型别名;
  • evaluateString 应该是你的评估函数,它目前只是一个未实现的存根 if;
  • sequenceU 您可能需要阅读 cats 有关它的文档:sequenceU
  • toEither 完全按照您的想法行事,它将 Validated[A,B] 转换为 Either[A,B].

正如@Michael 指出的那样,您也可以使用 traverseU 而不是 mapsequenceU

val validationResult: ListValidationResult[String] = 
  stringList.traverseU(evaluateString).toEither