suish
suish

Reputation: 3363

How to use for instead of flatMap/map in Scala?

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

Answers (2)

user2609980
user2609980

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:

For-comprehension and pattern matching

Upvotes: 3

Peter Neyens
Peter Neyens

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

Related Questions