for-comprehension yield 引发类型不匹配编译器错误

Loo*_*oom 1 scala yield compiler-errors type-mismatch for-comprehension

我想从Iterable[Try[Int]]所有有效值的列表中提取( Iterable[Int])

val test = List(
    Try(8), 
    Try(throw new RuntimeException("foo")), 
    Try(42), 
    Try(throw new RuntimeException("bar"))
)
Run Code Online (Sandbox Code Playgroud)

以下是从 打印所有有效值的方法test

for {
    n <- test
    p <- n
} println(p)

// Output
// 8
// 42
Run Code Online (Sandbox Code Playgroud)

但是,当我尝试将有效值保存到列表时,我收到了一个错误:

val nums: Seq[Int] = for {
    n <- list
    p <- n    // Type mismatch. Required: IterableOnce[Int], found Try[Int]
} yield(p)
println(nums)
Run Code Online (Sandbox Code Playgroud)

如何修复错误以及它为什么被提出?

Mar*_*lic 5

尝试收集

test.collect { case Success(value) => value }
// res0: List[Int] = List(8, 42)
Run Code Online (Sandbox Code Playgroud)

以对应于的 for-comprehension 格式

for { Success(p) <- test } yield p
Run Code Online (Sandbox Code Playgroud)

两者都使用构造函数模式,在幕后执行isInstanceOf类型测试,然后进行asInstanceOf类型转换。Verbosly 对应于类似的东西

test
  .filter (_.isInstanceOf[Success[Int]])
  .map    (_.asInstanceOf[Success[Int]].value)
Run Code Online (Sandbox Code Playgroud)

以下 for-comprehension 不起作用,因为其中的 monad 必须对齐

for {
  n <- test  // List monad
  p <- n     // does not align with Try monad
} yield (p)
Run Code Online (Sandbox Code Playgroud)

以上为理解脱糖

test.flatMap((n: Try[Int]) => n.map((p: Int) => p))
Run Code Online (Sandbox Code Playgroud)

并查看签名,flatMap我们看到它需要一个函数

Try[Int] => IterableOnce[Int]
Run Code Online (Sandbox Code Playgroud)

虽然我们提供

Try[Int] => Try[Int]
Run Code Online (Sandbox Code Playgroud)

因为n.map((p: Int) => p)返回Try[Int]。现在下面的理解是完全不同的野兽

for {
    n <- test
    p <- n
} println(p)
Run Code Online (Sandbox Code Playgroud)

因为没有yield它脱糖

test.foreach((n: Try[Int]) => n.foreach((p: Int) => println(p)))
Run Code Online (Sandbox Code Playgroud)

whereforeach期望类型的函数

Try[Int] => Unit
Run Code Online (Sandbox Code Playgroud)

我们确实提供了因为n.foreach((p: Int) => println(p))确实返回了Unit