2012-02-06 2 views
4

У меня есть объект ValidationScalaz проверки, проверки значения внутреннего

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

, что нужно сделать вторую проверку, чтобы проверить, если фактическое значение целого числа равно 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]]] 

Как можно получить также в ст 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]] 
} 

Выглядит не лаконичный и элегантный, хотя он работает

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

Второе решение от моей, но и выглядит более-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] 
} 

ответ

0

Использование flatMap, например, так:

v.flatMap(_.parseInt.fail.map(_.getMessage).validation) 
+0

Почему 'parseInt'? –

2

Ваше решение слишком сложно. Достаточно следующего!

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-жаргоне):

Validation[X, A] 
      => (A => Validation[X, B]] 
          => (via map) Validation[X, Validation[X, B]] 
                => (via join) Validation[X, B] 
+1

Привет, Для v = Some (100) .success [String] ваше решение возвращает Success (100), но я пытаюсь получить Success (Some (100)) И для v = None.success [String ] ваше решение возвращает Failure (обнаружено плохое значение), но я надеюсь увидеть Success (None) Дополнительные пояснения, почему мне это нужно: я получаю от проверки базы данных, которая содержит ошибки для доступа к данным или успешно загруженных данных. В базе данных данных фактически нет данных, и это не ошибка. Если существуют данные, я хочу проверить его для некоторых правил. –

2

Во-первых, давайте установим некоторые псевдонимы типа, потому что печатаю это неоднократно будет Старайтесь довольно быстро. Мы немного уберем вашу логику проверки, пока мы здесь.

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 эквивалентно вашей ст ситуации

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

или если вы чувствуете лямбда-у это могло бы быть

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

Далее мы выровняем эту вложенную проверку - мы собираемся вытащить монаду проверки, потому что на самом деле мы действительно хотим поведения fastfail здесь, хотя обычно это не так.

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

Так что теперь у нас есть Validation [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 

и по определению монады:

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)) 

Итак, теперь мы смотрим на нечто более цивилизованное. Я предполагаю, что есть какая-то обманка, которую нужно сыграть с плоской мачтой и траверсом, но у меня закончилось вдохновение.

Смежные вопросы