6

I am trying to come up with something similar to the following:

val s: Validation[String, Int] = 1.success
def s2(i: Int): Validation[String, Int] = i.success

val result = for {
  i <- s
  j <- List(1, 2)
  k <- s2(j)
} yield "fine";

The above code does not compile and I understand, syntactically it does not make sense.

I am trying to execute a list of validations in a monadic way. How do I achieve that?

sanjib
  • 593
  • 1
  • 4
  • 7
  • 4
    Hi it's a bit strange to see what you want to achieve. If you want to chain validations I suggest to look here(applicative) in line 97 maybe that helps:https://github.com/scalaz/scalaz/blob/master/example/src/main/scala/scalaz/example/ExampleValidation.scala – AndreasScheinert Aug 10 '11 at 12:46

2 Answers2

8

If you have a list of validations of A, you can turn it into a validation of lists of A using sequence:

List(1, 2).map(s2).sequence[({type l[a]=Validation[String, a]})#l, Int] 

(if I understand the question correctly). So you get

val result = for {
  i <- s
  k <- List(1, 2).map(s2).sequence[({type l[a]=Validation[String, a]})#l, Int] 
} yield "fine"
Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487
  • Sorry, answered too soon. It is almost what I was looking for. Here the all the validations in the list are computed. I was hoping to stop the computation once I receive the failure. How do i do that ? – sanjib Aug 10 '11 at 14:54
  • Can't test it at the moment, but try using `Stream` (i.e. lazy list) instead of `List`, or `List(1, 2).view.map(s2)...`. – Alexey Romanov Aug 10 '11 at 17:48
  • 1
    .view just doesn't compile. Explicitly created stream with Stream.from(-100) (I used a different s function, which ensures, that i is greater then 0) leads to stack overflow. Also note that you need to import Validation.Monad._ if you want the "fail first" semantics of sequence. – CheatEx Aug 10 '11 at 19:26
4

You seem to be using validation for the side effect. This is not what its ment for. You use the return values in functional programming.

Validation in a for comprehension continues with on success, but breaks of at a failure and returns the failure.

scala> def g(i: Int): Validation[String, Int] = { 
          println(i); if(i % 2 == 0) i.success else "odd".fail 
       }
g: (i: Int)scalaz.Validation[String,Int]

scala> val result = for {
     |   i <- g(1)
     |   j <- g(2)
     | } yield (i,j)
1
result: scalaz.Validation[String,(Int, Int)] = Failure(odd)

scala> val result = for {
     |   i <- g(2)
     |   j <- g(1)
     | } yield (i,j)
2
1
result: scalaz.Validation[String,(Int, Int)] = Failure(odd)


scala> val result = for {
     |   i <- g(2)
     |   j <- g(2)
     | } yield (i,j)
2
2
result: scalaz.Validation[String,(Int, Int)] = Success((2,2))


scala> val result = for {
     |   i <- g(1)
     |   j <- g(1)
     | } yield (i,j)
1
result: scalaz.Validation[String,(Int, Int)] = Failure(odd)
Ido Tamir
  • 3,017
  • 2
  • 19
  • 28