映射和减少/折叠 scalaz.Validation 的 HList [英] Map and reduce/fold over HList of scalaz.Validation

查看:45
本文介绍了映射和减少/折叠 scalaz.Validation 的 HList的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我从这样的事情开始:

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 但最后一行将停止工作,我不得不放弃一些静态安全性.于是我看向无形:

Now I thought it would be nice to reduce the boilerplate for better readability and for not having to explain to more junior team members what .toValidateNel and |@| mean. The first thought was List but then the last line would stop working and I'd have to give up some static safety. So I looked towards Shapeless:

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 的建议进行了尝试:

however, I can't even seem to get past the .map(...) bit. I've tried as per a suggestion on #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 上寻求帮助,但似乎人们没有现成的答案.但是,我真的很想学习如何解决这个问题,无论是出于实践还是学习目的.

I've asked for help on #scalaz but it doesn't seem something people just have an out of the box answer to. However, I'm really keen on learning how to solve this both for practical as well as learning purposes.

P.S.实际上,我的验证被包裹在 Kleisli[Va, A, B] 中,这样我就可以使用 >=> 来组成单独的验证步骤,但这似乎与问题是,在到达 .map(...) 时,所有 Kleisli 都将减少"为 Validation[String, A].

P.S. in reality my validations are wrapped inside Kleisli[Va, A, B] so that I could compose individual validation steps using >=> but that seems to be orthogonal to the issue as by the time that .map(...) is reached, all Kleislis will have been "reduced" to Validation[String, A].

推荐答案

这里是 shapeless 的样子-contribtraverse:

import scalaz._, Scalaz._
import shapeless._, contrib.scalaz._, syntax.std.tuple._

def nonEmpty[A] = (msg: String) => (a: Option[A]) => a.toSuccess(msg)

val postal: Option[String] = Some("00000")
val country: Option[String] = Some("us")

val params = (
  postal  |> nonEmpty[String]("no postal"),
  country |> nonEmpty[String]("no country")
)

然后:

object ToVNS extends Poly1 {
  implicit def validation[T] = at[Validation[String, T]](_.toValidationNel)
}

val result = traverse(params.productElements)(ToVNS).map(_.tupled)

现在 result 是一个 ValidationNel[String, (String, String)],你可以用它做任何你可以用糟糕的 ApplicativeBuilder 做的事情|@| 减少你会得到的东西.

Now result is a ValidationNel[String, (String, String)], and you can do anything with it that you could do with the awful ApplicativeBuilder thing you'd get from reducing with |@|.

这篇关于映射和减少/折叠 scalaz.Validation 的 HList的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆