Reputation: 3363
I'm in stack to understand how Scala for
works.
I think codes below could be written with for
though I don't have any idea how.
Could someone explain me how I can do that?
def foo: Future[Option[Int]] = ???
def bar: Future[Throwable Xor Option[Int]] = ???
def baz: Future[Option[Boolean]] = ???
foo.flatMap {
case Some(x) =>
Future.successful(x)
case None =>
bar.flatMap {
case Xor.Right(Some(x)) =>
baz.map {
case true => 1
case false => 0
}
case Xor.Right(None) =>
Future.successful(0)
case Xor.Left(_) =>
Future.successful(-1)
}
}
Upvotes: 3
Views: 406
Reputation: 10504
It is not possible to pattern match in for-comprehensions. See Allow pattern matching on type in for comprehensions.
Perhaps you can use Monad Transformers. I do want to implement your code in that manner, but I don't have time for that now. Maybe the hint can help you.
/Edit This is not completely correct as pointed out by the comment of Sergey. You can pattern match in for-comprehensions as long as all matches are of the same type. See this image taken from the second lesson of the first week of Functional Program Design in Scala Coursera Course where all patterns inherit from JSON
:
Upvotes: 3
Reputation: 9820
With all the branching inside the flatMap
functions, it won't be possible to write this as a for comprehension.
It is possible to replace pattern matching with a fold
method, but this may be a matter of personal preference.
Option("suish") match {
case Some(name) => s"hello $name"
case None => "hello world"
}
// is analogous to
Option("suish").fold("hello world")(name => s"hello $name")
I rewrote your pattern matching using the fold
methods of OptionT
(tutorial), XorT
and Option
, but I'm not sure if this is more readable than your nested pattern matches.
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import cats.implicits._
import cats.data.{Xor, XorT, OptionT}
def foo: Future[Option[Int]] = none[Int].pure[Future]
def bar: Future[Throwable Xor Option[Int]] = 2.some.right.pure[Future]
def baz: Future[Option[Boolean]] = true.some.pure[Future]
OptionT(foo).getOrElseF {
// foo : case None
XorT(bar).fold(
// bar : case Xor.Left
_ => -1.pure[Future],
barO => barO.fold(
// bar : case Xor.Right(None)
0.pure[Future])(
// bar : case Xor.Right(Some(x))
_ => baz.map(_.fold(0 /* ? */)(b => if (b) 1 else 0)))
).flatten
}
// Future[Int]
Upvotes: 4