Scala - 如何使用 cats 的 Validated monad 验证列表中的每个字符串?

Scala - how to validate every String in list using Validated monad from cats?

我有一个 Strings 的列表,我需要验证它们是否匹配某种模式:

def validate(strings: List[String]): Either[WrongStringError, List[String]] = {
    strings.foreach(s => checkString(s))
    Right(strings)
  }

private def checkString(s: String): Validated[WrongStringError, String] = {
  val pattern = .... //some regex
  Either.catchNonFatal(s.matches(pattern))
    .left
    .map(_ => WrongStringError(s"Given string: ${s} is not valid."))
  }.toValidated

但是,我想要实现的是将所有错误累积在一起。例如,如果 5 个字符串中有 3 个不正确,我希望将 return 错误告知用户。我想过使用 cats 中的 Validated monad,但没有得到结果。 我如何验证不正确的字符串列表和 return 错误列表?

I thought of using Validated monad from cats but I did not get result.

好吧,像 Validated (或任何 FP 数据结构) 这样的想法是将值组合在一起。

但是,您在这里没有编写任何内容,您只是调用 foreach,因此如果出现故障,您甚至不会收到错误,您将始终收到 Right

此外,如果您想收集所有错误,您需要使用某种 (非空) 容器,例如 NonEmptyChain.

最后,我有一个值的集合和一个将这些值转换为有效值的函数的这种常见模式,我想将所有这些效果收集/组合到列表的单个效果中,称为 traverse.

奖励积分,这种使用同构效果类型的常见模式看起来与我的正常效果完全一样,只是它只是 Applicative 而不是 Monad 以提供不同的 (parallel) 行为是如此普遍,以至于 cats 引入了 Parallel 类型类和组合器 (例如 parTraverse) 避免样板文件。

无论如何,这就是代码的样子:

import cats.data.NonEmptyChain
import cats.syntax.all._

type Error = String

def validate(strings: List[String]): Either[NonEmptyChain[Error], List[String]] =
  strings.parTraverse { s =>
    checkString(s).toEitherNec
  }

def checkString(s: String): Either[Error, String] = {
  val pattern = ""
  Either.cond(
    test = s.matches(pattern),
    right = s,
    left = "Given string: ${s} is not valid."
  )
}

顺便说一句,我建议你多学习一下 FP。
我可能会向您推荐 Rob Norris 的演讲“Functional Programming with Effects”和 (免费) 一书“Scala with Cats”。