如何在 Scala 中使用 for 而不是 flatMap/map?
How to use for instead of flatMap/map in Scala?
我正在努力了解 Scala for
的工作原理。
我认为下面的代码可以用 for
编写,但我不知道如何编写。
谁能解释一下我该怎么做?
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)
}
}
无法在 for-comprehensions 中进行模式匹配。参见 Allow pattern matching on type in for comprehensions。
也许你可以使用 Monad Transformers。我确实想以这种方式实现您的代码,但我现在没有时间。或许提示可以帮到你。
/Edit 正如谢尔盖的评论所指出的,这并不完全正确。只要所有匹配都是同一类型,就可以在 for-comprehensions 中进行模式匹配。查看这张取自 second lesson of the first week of Functional Program Design in Scala Coursera Course 的图片,其中所有模式都继承自 JSON
:
由于 flatMap
函数中的所有分支,不可能将其写成 for comprehension。
可以用 fold
方法替换模式匹配,但这可能是个人喜好问题。
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")
我使用 OptionT
(tutorial), XorT
和 Option
的 fold
方法重写了您的模式匹配,但我不确定这是否比您的嵌套模式匹配更具可读性。
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]
我正在努力了解 Scala for
的工作原理。
我认为下面的代码可以用 for
编写,但我不知道如何编写。
谁能解释一下我该怎么做?
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)
}
}
无法在 for-comprehensions 中进行模式匹配。参见 Allow pattern matching on type in for comprehensions。
也许你可以使用 Monad Transformers。我确实想以这种方式实现您的代码,但我现在没有时间。或许提示可以帮到你。
/Edit 正如谢尔盖的评论所指出的,这并不完全正确。只要所有匹配都是同一类型,就可以在 for-comprehensions 中进行模式匹配。查看这张取自 second lesson of the first week of Functional Program Design in Scala Coursera Course 的图片,其中所有模式都继承自 JSON
:
由于 flatMap
函数中的所有分支,不可能将其写成 for comprehension。
可以用 fold
方法替换模式匹配,但这可能是个人喜好问题。
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")
我使用 OptionT
(tutorial), XorT
和 Option
的 fold
方法重写了您的模式匹配,但我不确定这是否比您的嵌套模式匹配更具可读性。
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]