是否有更简洁的方式,即没有嵌套的for expressions
来编写以下f
,g
和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
我猜测我可以使用Monad变形金刚,但我不理解它们。
答案 0 :(得分:4)
如果您使用的是Foo[Qux[A]]
类型,其中Foo
和Qux
都是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)