for-comppresion возвращает None, если хотя бы один компонент в `for` равен None - PullRequest
1 голос
/ 14 мая 2019

Мне трудно понять механизм использования for-компрессии в Scala.Например, если у меня есть

val x = for {
  i <- Option(1)
  j <- Option(2)
  k <- Option(3)
} yield (i,j,k)

x - это x: Option[(Int, Int, Int)] = Some((1,2,3)).Однако, если хотя бы один из компонентов имеет значение None, например,

val x = for {
  i <- Option(1)
  j <- Option(2)
  k <- None
} yield (i,j,k)

, тогда x равно x: Option[(Int, Int, Nothing)] = None, хотя я действительно надеялся увидеть что-то вроде: x: Option[(Int, Int, Nothing)] = Some((1,2,None)).

Я проверил FAQ из официальной документации Scala , где конкретно указано, что for-comprehension является комбинацией flatmap и map.Но мне все еще трудно понять, что x - это None.

Мне кажется, я пропустил некоторые важные понятия о flatmap и map разнице.

1 Ответ

5 голосов
/ 14 мая 2019

Первый для понимания "десугарс" в:

val x = Option(1).flatMap(
  i => Option(2).flatMap(
    j => Option(3).map(
      k => (i, j, k)
    )
  )
)

Как вы можете видеть - первая опция отображается плоско с помощью функции, которая принимает свое значение (если оно существует) и возвращает 3-кортеж (используя аналогичную операцию для второй опции). Независимо от того, что это за функция - все выражение имеет вид:

val x = Option(1).flatMap(f)

Теперь, если мы заменим Option(1) на None (как вы это сделали во втором выражении), мы бы ясно получили None:

val x = None.flatMap(f) // None, for any f

Результат, который вы ожидали (Some((None, 2, 3))), не слишком полезен - поскольку он будет иметь различных типов для разных входных данных: будет ли (Option[Int], Int, Int)? Или (Int, Int, Int)? Или (Option[Int], Option[Int], Option[Int])? Действительно, единственный распространенный тип для (None, 2, 3), (1, None, 3) и (1, 2, None) - это не очень полезный (Any, Any, Any).

...