[英]Scalaz Validation, validate inner value
I have a Validation object 我有一个Validation对象
val v = Validation[String, Option[Int]]
I need to make a second validation, to check if actual Integer value is equals to 100 for example. 我需要进行第二次验证,以检查实际的Integer值是否等于100。 If I do 如果我做
val vv = v.map(_.map(intValue => if (intValue == 100)
intValue.success[String]
else
"Bad value found".fail[Integer]))
I get: 我明白了:
Validation[String, Option[Validation[String, Int]]]
How is it possible to get vv also as Validation[String, Option[Int]] in most concise way 怎样才能以最简洁的方式将vv作为Validation [String,Option [Int]]
========= =========
Found possible solution from my own: 从我自己找到可能的解决方案:
val validation: Validation[String, Option[Int]] = Some(100).success[String]
val validatedTwice: Validation[String, Option[Int]] = validation.fold(
_ => validation, // if Failure then return it
_.map(validateValue _) getOrElse validation // validate Successful result
)
def validateValue(value: Int): Validation[String, Option[Int]] = {
if (value == 100)
Some(value).success[String]
else
"Bad value".fail[Option[Int]]
}
Looks not concise and elegant although it works 尽管它有效但看起来并不简洁优雅
============== ==============
Second solution from my own, but also looks over-compicated: 我自己的第二个解决方案,但也看起来过于复杂:
val validatedTwice2: Validation[String, Option[Int]] = validation.flatMap(
_.map(validateValue _).map(_.map(Some(_))) getOrElse validation)
def validateValue(value: Int): Validation[String, Int] = {
if (value == 100)
value.success[String]
else
"Bad value".fail[Int]
}
First, let's set up some type aliases because typing this out repeatedly will get old pretty fast. 首先,让我们设置一些类型的别名,因为反复输入这个别名会很快变旧。 We'll tidy up your validation logic a little too while we're here. 当我们在这里时,我们会稍微整理你的验证逻辑。
type V[X] = Validation[String, X]
type O[X] = Option[X]
def checkInt(i: Int): V[Int] = Validation.fromEither(i != 100 either "Bad value found" or i)
val v: V[O[Int]] = _
this is where we're starting out - b1 is equivalent to your vv situation 这是我们开始的地方 - b1相当于你的vv情况
val b1: V[O[V[Int]]] = v.map(_.map(checkInt))
so let's sequence the option to flip over the V[O[V[Int]]] into a V[V[O[Int]]] 所以让我们按顺序选择将V [O [V [Int]]]翻转成V [V [O [Int]]]
val b2: V[V[O[Int]]] = v.map(_.map(checkInt)).map(_.sequence[V, Int])
or if you're feeling lambda-y it could have been 或者,如果你感觉到lambda-y它可能是
sequence[({type l[x] = Validation[String, x]})#l, Int]
next we flatten out that nested validation - we're going to pull in the Validation monad because we actually do want the fastfail behaviour here, although it's generally not the right thing to do. 接下来我们讨论了嵌套验证 - 我们将引入Validation monad,因为我们确实想要这里的fastfail行为,尽管通常不是正确的做法。
implicit val monad = Validation.validationMonad[String]
val b3: V[O[Int]] = v.map(_.map(checkInt)).map(_.sequence[V, Int]).join
So now we've got a Validation[String, Option[Int]], so we're there, but this is still pretty messy. 所以现在我们有了一个验证[String,Option [Int]],所以我们就在那里,但这仍然非常混乱。 Lets use some equational reasoning to tidy it up 让我们用一些等式推理来整理它
By the second functor law we know that: 根据第二个仿函数法,我们知道:
X.map(_.f).map(_.g) = X.map(_.f.g) =>
val i1: V[O[Int]] = v.map(_.map(checkInt).sequence[V, Int]).join
and by the definition of a monad: 并根据monad的定义:
X.map(f).join = X.flatMap(f) =>
val i2: V[O[Int]] = v.flatMap(_.map(checkInt).sequence[V, Int])
and then we apply the free theorem of traversal: 然后我们应用遍历的自由定理:
(I struggled with that bloody paper so much, but it looks like some of it sunk in!): (我在那张血腥的纸上挣扎得太厉害了,但看起来它有些沉入其中!):
X.map(f).sequence = X.traverse(f andThen identity) = X.traverse(f) =>
val i3: V[O[Int]] = v.flatMap(_.traverse[V, Int](checkInt))
so now we're looking at something a bit more civilised. 所以现在我们正在寻找一些更文明的东西。 I imagine there's some trickery to be played with the flatMap and traverse, but I've run out of inspiration. 我想有一些技巧可以使用flatMap和遍历,但我已经没有灵感了。
Your solution is over-complicated. 您的解决方案过于复杂。 The following will suffice! 以下就足够了!
v flatMap (_.filter(_ == 100).toSuccess("Bad value found"))
The toSuccess
comes from OptionW
and converts an Option[A]
into a Validation[X, A]
taking the value provided for the failure case in the event that the option is empty. 所述toSuccess
来自OptionW
和转换的Option[A]
成Validation[X, A]
以提供用于在故障情况下,所述选项为空的情况下的值。 The flatMap
works like this: flatMap
工作方式如下:
Validation[X, A]
=> (A => Validation[X, B])
=> (via flatMap) Validation[X, B]
That is, flatMap
maps and then flattens ( join
in scalaz-parlance): 也就是说, flatMap
映射然后展平( join
scalaz-parlance):
Validation[X, A]
=> (A => Validation[X, B]]
=> (via map) Validation[X, Validation[X, B]]
=> (via join) Validation[X, B]
使用flatMap
,如下所示:
v.flatMap(_.parseInt.fail.map(_.getMessage).validation)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.