suppose I have
type VS[A] = Validation[String, A]
val v: VS[Option[A]]
val f: A => VS[B]
I want to get a result of type VS[Option[B]] but if v is a Success(None), the result should also be a Success(None). Here's an example:
scala> val v: VS[Option[String]] = some("4.5").success
v: VS[Option[String]] = Success(Some(4.5))
scala> val f = (s : String) => (try { s.toInt.success } catch { case x => x.getMessage.fail }): VS[Int]
f: String => VS[Int] = <function1>
Then:
scala> import Validation.Monad._
import Validation.Monad._
scala> (v map2 f map (_.sequence)).join
res4: scalaz.Validation[String,Option[Int]] = Failure(For input string: "4.5")
The success case is:
scala> val v: VS[Option[String]]= some("5").success
v: VS[Option[String]] = Success(Some(5))
scala> (v map2 f map (_.sequence)).join //UGLY composition
res7: scalaz.Validation[String,Option[Int]] = Success(Some(5))
And the empty case is:
scala> val v: VS[Option[String]]= none[String].success
v: VS[Option[String]] = Success(None)
scala> (v map2 f map (_.sequence)).join
res6: scalaz.Validation[String,Option[Int]] = Success(None)
Is there a "nicer" way of doing this (possibly involving kleisli composition or monad transformers)?
The monad transformer
OptionTdoes exactly what you want here, and itsflatMapFmethod makes usage a clean one-liner.I'm going to use Scalaz 7's disjunction type (
\/) instead ofValidationin this example, since the latter isn't a monad in Scalaz 7, but the principle is the same.Now we can write the following:
Or equivalently:
Or the success case:
Or the empty case:
As desired.