Nested expressions

Is there a cleaner way i.e. without nested for expressions

, write the following functions f

, g

and doIt

?

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

def f(x: Int): Future[Either[String, Int]] = Future(Right(100))

def g(x: Either[String, Int], y: Int): Future[Either[String, Int]] = 
   Future { x match {
    case Right(i)  => Right(i + y)
    case Left(err) => Left(err)
}}

def doIt: Future[Either[String, Int]] = for {
    x <- for { a <- f(100) } yield a
    y <- for { a <- g(x, 25) } yield a
} yield y

      

I am contemplating that I can use Monad Transformers, but I do not understand them.

+3


source to share


3 answers


If you work with these types of as Foo[Qux[A]]

, where both Foo

and Qux

are monads, and you will find that writing many nested for

-posobstvy, the first thing you need to do is check Scalaz (or cats ) to QuxT

monad transformer. This will allow you to work with values QuxT[Foo, A]

monadically with one level for

s.

As the other answers for

suggest , you don't actually need nested- manuals in your case given your definition g

. I assume you want to work with values ​​entirely internally Future[Either[String, ?]]

, without a noisy method g

, in which case you want EitherT[Future, String, Int]

:

import scalaz._, Scalaz._
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

def f(x: Int): EitherT[Future, String, Int] =
  EitherT.fromEither(Future[Either[String, Int]](Right(100)))

// Or just:
// def f(x: Int): EitherT[Future, String, Int] = EitherT.right(Future(100))

def doIt: EitherT[Future, String, Int] = f(100).map(_ + 25)

      



Eventually you would write doIt.run

to get Future[Either[String, Int]]

:

scala> doIt.run.onSuccess { case e => println(e) }
\/-(125)

      

This is the same output that your implementation gives (except that we have a Scalaz splitting type).

+4


source


Sure. You don't need nested for

-understanding:



def doIt: Future[Either[String, Int]] = for {
  x <- f(100)
  y <- g(x, 25)
} yield y

      

0


source


If you are ready to completely part with for

:

def doIt: Future[Either[String, Int]] = f(100).flatMap(x => g(x, 25)

      

Or even shorter:

def doIt: Future[Either[String, Int]] = f(100).flatMap(g(_, 25)

      

0


source







All Articles