簡體   English   中英

Scalaz驗證,驗證內在價值

[英]Scalaz Validation, validate inner value

我有一個Validation對象

val v = Validation[String, Option[Int]]

我需要進行第二次驗證,以檢查實際的Integer值是否等於100。 如果我做

val vv = v.map(_.map(intValue => if (intValue == 100) 
                               intValue.success[String] 
                           else 
                               "Bad value found".fail[Integer]))

我明白了:

Validation[String, Option[Validation[String, Int]]]

怎樣才能以最簡潔的方式將vv作為Validation [String,Option [Int]]

=========

從我自己找到可能的解決方案:

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]]
}

盡管它有效但看起來並不簡潔優雅

==============

我自己的第二個解決方案,但也看起來過於復雜:

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]
}

首先,讓我們設置一些類型的別名,因為反復輸入這個別名會很快變舊。 當我們在這里時,我們會稍微整理你的驗證邏輯。

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]] = _

這是我們開始的地方 - b1相當於你的vv情況

val b1: V[O[V[Int]]] = v.map(_.map(checkInt))

所以讓我們按順序選擇將V [O [V [Int]]]翻轉成V [V [O [Int]]]

val b2: V[V[O[Int]]] = v.map(_.map(checkInt)).map(_.sequence[V, Int])

或者,如果你感覺到lambda-y它可能是

sequence[({type l[x] = Validation[String, x]})#l, Int]

接下來我們討論了嵌套驗證 - 我們將引入Validation monad,因為我們確實想要這里的fastfail行為,盡管通常不是正確的做法。

implicit val monad = Validation.validationMonad[String]
val b3: V[O[Int]] = v.map(_.map(checkInt)).map(_.sequence[V, Int]).join

所以現在我們有了一個驗證[String,Option [Int]],所以我們就在那里,但這仍然非常混亂。 讓我們用一些等式推理來整理它

根據第二個仿函數法,我們知道:

X.map(_.f).map(_.g) = X.map(_.f.g) =>
    val i1: V[O[Int]] = v.map(_.map(checkInt).sequence[V, Int]).join

並根據monad的定義:

X.map(f).join = X.flatMap(f) =>
    val i2: V[O[Int]] = v.flatMap(_.map(checkInt).sequence[V, Int])

然后我們應用遍歷的自由定理:
(我在那張血腥的紙上掙扎得太厲害了,但看起來它有些沉入其中!):

X.map(f).sequence = X.traverse(f andThen identity) = X.traverse(f) =>
    val i3: V[O[Int]] = v.flatMap(_.traverse[V, Int](checkInt))

所以現在我們正在尋找一些更文明的東西。 我想有一些技巧可以使用flatMap和遍歷,但我已經沒有靈感了。

您的解決方案過於復雜。 以下就足夠了!

v flatMap (_.filter(_ == 100).toSuccess("Bad value found"))

所述toSuccess來自OptionW和轉換的Option[A]Validation[X, A]以提供用於在故障情況下,所述選項為空的情況下的值。 flatMap工作方式如下:

Validation[X, A] 
          => (A => Validation[X, B]) 
                                => (via flatMap) Validation[X, B]

也就是說, 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM