嵌套表达式

时间:2015-07-09 18:24:01

标签: scala

是否有更简洁的方式,即没有嵌套的for expressions来编写以下fgdoIt函数?

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

我猜测我可以使用Monad变形金刚,但我不理解它们。

3 个答案:

答案 0 :(得分:4)

如果您使用的是Foo[Qux[A]]类型,其中FooQux都是monad,而您发现您正在撰写大量嵌套for - 理解,你应该做的第一件事是检查Scalaz(或cats)是否有QuxT monad变换器。这样,您就可以使用QuxT[Foo, A]的单个级别单独使用for个值。

正如其他答案所指出的那样,根据您对for的定义,您实际上并不需要嵌套的g - 理解。我将假设您希望在Future[Either[String, ?]]内一直使用值,而不使用嘈杂的g方法,在这种情况下,您需要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)

最后,您需要撰写doIt.run来获取Future[Either[String, Int]]

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

您的实现给出了相同的结果(除了我们有Scalaz的析取类型)。

答案 1 :(得分:0)

不确定。你根本不需要嵌套的for - 理解:

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

答案 2 :(得分:0)

如果您愿意完全放弃for理解:

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

甚至更短:

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