【问题标题】:Scalaz validation and ApplicativeBuilder limitsScalaz 验证和 ApplicativeBuilder 限制
【发布时间】:2011-04-21 07:30:14
【问题描述】:

我们在项目中使用 scalaz 验证特性来验证 HTTP 参数。常见的情况是仅在所有验证值都有效时才采用少量验证值并执行必要的操作,否则返回错误列表:

(pavam1Val.liftFailNel |@|
 param2Val.liftFailNel |@|
 param3Val.liftFailNel) {
    getSomeResponse(_, _, _)
}

这很好用,直到我们必须使用超过 8 个参数,因为 |@|运算符构造 ApplicativeBuilder,它限制为 8 个参数。是否有另一种方法来执行这种一次性验证,最好是保持代码可读?

【问题讨论】:

  • 我们在下一版本中将 ApplicativeBuilder 的(任意)限制更新为 12。

标签: validation scala scalaz


【解决方案1】:

您想使用<*> 方法,同时调用map(或,如果您愿意)。您可以无限期地继续使用<*>

scala> val param1Val = success[String, Int](7)                              
param1Val: scalaz.Validation[String,Int] = Success(7)

scala> val param2Val = failure[String, Int]("abc")                          
param2Val: scalaz.Validation[String,Int] = Failure(abc)

scala> val param3Val = success[String, Int](9)                              
param3Val: scalaz.Validation[String,Int] = Success(9)

scala> val r = param1Val <*> (param2Val <*> (param3Val map getSomeResponse))
r: scalaz.Validation[String,Int] = Failure(abc)

【讨论】:

  • 别忘了getSomeResponse需要是柯里化函数,即Int =&gt; Int =&gt; Int =&gt; Int
  • 我们没有倒序的论点吗?我的意思是得到与我们需要写param3Val &lt;*&gt; (param2Val &lt;*&gt; (param1Val map getSomeResponse))的问题相同的结果。
【解决方案2】:

还有几种方法:

  1. 将相关函数提升到Validation 上下文,然后将其应用于值。

    getSomeResponse.lift[({ type L[X] = Validation[Y, X] })#L] apply (
      param1Val, param2Val, param3Val
    )
    
  2. 使用单子理解。

    for {
      x1 <- param1Val
      x2 <- param2Val
      x3 <- param3Val
    } yield getSomeResponse(x1, x2, x3)
    

【讨论】:

  • 当然,monadic 版本不会累积错误,只是解决第一个错误。
  • 虽然在这里,提升会使用 Functor 实例,所以它也会退出。
  • ron,否。提升 arity 1 函数使用 Functor 实例。提升具有更大数量的函数使用 Applicative 实例。所以它不会退出。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多