的我开始了这样的事情:Map和Reduce /折叠HList scalaz.Validation
def nonEmpty[A] = (msg: String) => (a: Option[A]) => a.toSuccess(msg)
val postal: Option[String] = request.param("postal")
val country: Option[String] = request.param("country")
val params =
(postal |> nonEmpty[String]("no postal")).toValidationNel |@|
(country |> nonEmpty[String]("no country")).toValidationNel
params { (postal, country) => ... }
现在,我认为这将是很好的,以减少对样板更好的可读性和不必解释更多的初级队员是什么.toValidateNel
和|@|
的意思。第一个想法是List
但最后一行将停止工作,我不得不放弃一些静态安全。所以,我看向无形:
import shapeless._; import poly._; import syntax.std.tuple._
val params = (
postal |> nonEmpty[String]("no postal"),
country |> nonEmpty[String]("no country")
)
params.map(_.toValidatioNel).reduce(_ |@| _)
然而,我甚至不能似乎让过去的.map(...)
位。我试着按照#scalaz上的建议:
type Va[+A] = Validation[String, A]
type VaNel[+A] = ValidationNel[String, A]
params.map(new (Va ~> VaNel) { def apply[T](x: Va[T]) = x.toValidationNel })
...无济于事。
我向#scalaz寻求帮助,但似乎并没有什么人只是有一个开箱即用的答案。不过,我非常热衷于学习如何解决这个问题,既为实践也为学习目的。
P.S.实际上,我的验证被封装在Kleisli[Va, A, B]
之内,因此我可以使用>=>
组合单个验证步骤,但似乎与问题正交,因为到达.map(...)
时,所有Kleisli
将被“减少”为Validation[String, A]
。
你一定需要将'Poly1'定义为一个对象(针对与稳定标识符有关的各种古怪的Scala相关原因)。这看起来很像遍历,而无形contrib的“遍历”可以让你一步完成'reduce(_ | @ | _)'的'toValidationNel'和(道义等价物)。 – 2014-10-16 17:45:36
另请参阅我的隐约相关的博客文章[这里](http://meta.plasm.us/posts/2013/06/05/applicative-validation-syntax/)。 – 2014-10-16 17:45:57