for-comprehension yield raises type mismatch compiler error

柔情痞子 提交于 2020-05-17 03:42:08

问题


I want to extract from Iterable[Try[Int]] a list of all valid values (Iterable[Int])

val test = List(
    Try(8), 
    Try(throw new RuntimeException("foo")), 
    Try(42), 
    Try(throw new RuntimeException("bar"))
)

The following is the way to print all valid values from test:

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

// Output
// 8
// 42

However, when I tried to save the valid values to list I have received an error:

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

How to fix the error and why it was raised?


回答1:


Try collect

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

In a for-comprehension format that corresponds to

for { Success(p) <- test } yield p

Both make use of Constructor Patterns which under the hood perform isInstanceOf type test followed by asInstanceOf type cast. Verbosly that corresponds to something like

test
  .filter (_.isInstanceOf[Success[Int]])
  .map    (_.asInstanceOf[Success[Int]].value)

The following for-comprehension does not work because the monads in it have to align

for {
  n <- test  // List monad
  p <- n     // does not align with Try monad
} yield (p)

The above for-comprehension desugars to

test.flatMap((n: Try[Int]) => n.map((p: Int) => p))

and looking at the signature of flatMap we see it expects a function

Try[Int] => IterableOnce[Int]

whilst we provide

Try[Int] => Try[Int]

because n.map((p: Int) => p) returns Try[Int]. Now the following for-comprehension is a whole different beast

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

because of the absence of yield it desugars to

test.foreach((n: Try[Int]) => n.foreach((p: Int) => println(p)))

where foreach expects a function of type

Try[Int] => Unit

which we indeed provide because n.foreach((p: Int) => println(p)) indeed returns Unit.




回答2:


You can also try:

val nums: Seq[Int] = list.map(_.toOption).flatten

or

val nums: Seq[Int] = list.flatMap(_.toOption)


来源:https://stackoverflow.com/questions/61763561/for-comprehension-yield-raises-type-mismatch-compiler-error

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!