Hey Tim
You are trying to use Validation as a Monad here, which is not what it was meant for. If you change the return type of f0, f1, and f2 to
EitherT[Future,String,String], you can use the results directly in a for-comprehension:
val f1: EitherT[Future,String,String] = EitherT(Promise.successful("foo".right))
def f2 (s: String): EitherT[Future,String,String] = ...
def f3 (s: String): EitherT[Future,String,String] = ...
val q: EitherT[Future,String,String] = for {
x <- f1 //x is a String
y <- f2(x)
z <- f3(x)
} yield z
Note, that in this case the errors of the calls to f2 and f3 will not be accumulated. You can achieve error accumulation by first
transferring the EitherT[Future,String,String] to a Future[Validation[String,String]] and then using its applicative functor. In that
case it might make more sense, to accumulate errors in a NonEmptyList. Otherwise you will just concatenate the error Strings.
Please tell me, if you need more help with the interconversion between \/ and Validation.
As an alternative, if you want to stick to your version of the code, you can transfer a Validation[String,Future[A]] to
a Future[Validation[String,A]] via .sequence:
val r: Future[Future[Validation[String,Validation[String,String]]]] =
q map { _.sequence }
In the end this should lead to a Future[Future[Validation[String,Validation[String,String]]]]
which you can the flatten further (in case of Future via join, in case of Validation via fold).
Cheers, Stefan