For comprehensions are just syntax sugar for a sequence of flatMap
calls. Because of this, not just any Scala code can go inside your for comprehension. The following is one of the things you are trying to do that is not legal Scala:
//This does not compile because normal if-else statements are not valid inside a for comprehension
object Example1 {
def f(o: Option[Int]): Option[Int] = for {
x <- o
if (x < 0) "return some value"
else { //attempting to continue the for comprehension
y <- o
}
} yield ??? //what would we yield here?
}
The if
keyword in a for comprehension is used for guards:
object Example2 {
def f(o: Option[Int]): Option[Int] = for {
x <- o
if x >= 0
} yield x
//f and f2 are equivalent functions
def f2(l: Option[Int]): Option[Int] = l.filter(_ >= 0)
}
But that doesn't look like what you want. It looks like you're trying to keep track of exceptions as you run each step. The Try
Monad does exactly this and can be used in a for comprehension. Note the equivalent Scala code that uses flatMap
calls instead of a for comprehension. I recommend writing the function with all the nested flatMap
calls before trying to convert to the prettier for comprehension syntax if you're getting stuck. Checkout this answer for some examples of how to do this.
// myFunc1 is equiv to myFunc2 is equiv to myFunc3
// they only differ in syntax
object Example3 {
import scala.util.Try
def runStepA[A](in: A): Try[A] = ???
def runStepB[A](in: A): Try[A] = ???
def runStepC[A](in: A): Try[A] = ???
def myFunc1[A](input: A): Try[A] = for {
nonErrorResultA <- runStepA(input)
nonErrorResultB <- runStepB(nonErrorResultA)
nonErrorResultC <- runStepC(nonErrorResultB)
} yield nonErrorResultC
def myFunc2[A](input: A): Try[A] =
runStepA(input).flatMap {
nonErrorResultA => runStepA(nonErrorResultA).flatMap {
nonErrorResultB => runStepB(nonErrorResultB).flatMap {
nonErrorResultC => runStepC(nonErrorResultC)
}
}
}
def myFunc3[A](input: A): Try[A] =
runStepA(input).flatMap {
runStepA(_).flatMap {
runStepB(_).flatMap {
runStepC
}
}
}
}