【问题标题】:In Scala Cats Validated, how can combine ordered validations在 Scala Cats Validated 中,如何组合有序验证
【发布时间】:2017-05-03 10:12:03
【问题描述】:

https://gist.github.com/satyagraha/897e427bfb5ed203e9d3054ac6705704 中,我发布了一个似乎合理的 Scala Cats 验证方案,但我还没有找到一个非常简洁的解决方案。

本质上,有一个两阶段验证,其中单个字段被验证,然后调用一个类构造函数,由于内部检查可能会抛出(通常这可能不在我的控制范围内更改,因此异常处理代码)。如果任何字段验证失败,我们希望不调用构造函数,但也希望将任何构造函数失败合并到最终结果中。 “快速失败”绝对适合两阶段检查。

这是一种flatMap 问题,cats.data.Validated 框架似乎通过cats.data.Validated#andThen 操作处理。但是,正如您在代码中看到的那样,我找不到一个特别巧妙的解决方案。 cats.syntax.CartesianBuilder 上可用的操作数量非常有限,我不清楚如何将其与 andThen 操作链接。

欢迎任何想法!注意有一个 Cats 问题 https://github.com/typelevel/cats/issues/1343 可能是相关的,不确定。

【问题讨论】:

    标签: scala validation scala-cats


    【解决方案1】:

    对于快速失败的链式验证,使用Either 比使用Validated 更容易。您可以轻松地从Either 切换到Validated,反之亦然,具体取决于您是否需要累积错误。

    您的问题的一个可能解决方案是为 User 创建一个智能构造函数,它返回一个 Either[Message, User] 并将其与 Validated[Message, (Name, Date)] 一起使用。

    import cats.implicits._
    import cats.data.Validated
    
    def user(name: Name, date: Date): Either[Message, User] = 
      Either.catchNonFatal(User(name, date)).leftMap(Message.toMessage)
    
    // error accumulation -> Validated
    val valids: Validated[Message, (Name, Date)] = 
      (validateName(nameRepr) |@| validateDate(dateDepr)).tupled
    
    // error short circuiting -> either
    val userOrMessage: Either[Message, User] =
      valids.toEither.flatMap((user _).tupled)
    
    // Either[Message,User] = Right(User(Name(joe),Date(now)))
    

    【讨论】:

      【解决方案2】:

      我会创建一个辅助二阶函数来包装抛出异常的函数:

      def attempt[A, B](f: A => B): A => Validated[Message, B] = a => tryNonFatal(f(a))
      

      另外,案例类的默认同伴扩展了FunctionN trait,所以不需要(User.apply _).tupled,它可以缩短为User.tupled(在自定义同伴上,你需要写extends ((...) => ...))apply覆盖将自动生成)

      所以我们最终使用andThen

      val valids = validateName(nameRepr) |@| validateDate(dateDepr)
      val res: Validated[Message, User] = valids.tupled andThen attempt(User.tupled)
      

      【讨论】:

      • 这看起来是一个很好的解决方案,并且似乎可以扩展到更一般的情况。谢谢!
      • 如果它可以为任何人节省一些时间...该符号代表product 方法
      • @Lasf 实际上,2020 年猫的编写方式是使用元组。所以,像(validateName(..), validateDate(..)).tupled andThen attempt(User.tupled)
      猜你喜欢
      • 2019-06-04
      • 1970-01-01
      • 1970-01-01
      • 2017-02-08
      • 2019-08-29
      • 1970-01-01
      • 2017-09-25
      • 1970-01-01
      • 2019-03-09
      相关资源
      最近更新 更多