【问题标题】:Converting flatMap to for-comprehension将 flatMap 转换为便于理解
【发布时间】:2014-06-11 06:52:10
【问题描述】:

给定foobar

scala> def foo: Try[Seq[String]] = Success(List("good", "job"))
foo: scala.util.Try[Seq[String]]

scala> def bar(x: String): Try[String] = Try(x)
bar: (x: String)scala.util.Try[String]

如何将此flatMap 转换为for-comprehension

scala> foo.flatMap(a => Try(a.map(c => bar(c))))
res48: scala.util.Try[Seq[scala.util.Try[String]]] = 
         Success(List(Success(good), Success(job)))

请注意,我将上述内容作为对 Using for-comprehension, Try and sequences in Scala 的答复,但我无法将其转换为 for-comphension

【问题讨论】:

  • 所以你想要一个Try[Seq] 还是你想要Seq[Try]?另外,Failure 在第一种情况下是否会失败?空的SeqFailure 的同义词吗?
  • 好问题。我想Try[Seq[Try[String]]] 没有任何意义。您如何理解我提到的问题中的返回类型 - stackoverflow.com/questions/23265227/…
  • 你为什么在你的第一个函数中将成功转化为尝试?
  • 像这样投射 ADT 是很典型的,@AndreasNeumann。可以说,ML/OCaml 和 Haskell 是自动完成的;例如Just 3 的类型在 Haskell 中是 Maybe Int; Scala 没有真正的 ADT,因此需要显式强制转换来模仿这些语义。

标签: scala for-comprehension flatmap


【解决方案1】:

你不能。一个 for-comprehension 只能是一系列 flatMap 调用,后跟一个 map(或所有 foreach 调用)。对Try 的调用打破了链条。您摆脱了Try 并使用map,但是两个map 调用也不能成为一个单一的理解。

Try.flatMap 将捕获传递给flatMap 的函数中发生的错误,因此我们可以通过在bar 的结果上调用get 来简化返回类型:

foo.map(a => a.map(c => bar(c).get))

我们可以通过像这样缩进其中两个来非常接近一个单一的理解:

for {
  a <- foo
} yield for {
  c <- a
} yield bar(c).get

产生:

res12: scala.util.Try[Seq[String]] = Success(List(good, job))

【讨论】:

    【解决方案2】:

    这个:

    foo.flatMap(a => Try(a.map(c => bar(c))))
    

    相当于:

    for {
      a <- foo
    } yield a.map(c => bar(c))
    

    至于将内部map“扁平化”为相同的for-comprehension——如果您希望结果为(即Try 的2 个级别),则没有意义:

    Success(List(Success(good), Success(job)))
    

    虽然我的直觉告诉我,您可能希望将List[Try[String]] 压平为List[String](使用例如.map(_.toOption).flatten),我猜wingedsubmariner 也建议这样做。

    【讨论】:

      猜你喜欢
      • 2014-10-14
      • 1970-01-01
      • 2013-01-13
      • 2018-08-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多