Почему flatMap на Векторе[Option[Int]], результат функции отображения которого не является вектором[Option[Int]], допустим?


Например,

Vector(Some(1), Some(2), Some(3), None).flatMap{
  n => n
}

Производит Vector(1, 2, 3) вместо того, чтобы давать ошибку. Как я уже видел в других языках, flatMap используется, когда у вас есть функция отображения, которая производит вложенность, поэтому я ожидал бы, что это будет допустимый flatMap:

Vector(1, 2, 3).flatMap{
  eachNum => Vector(eachNum)
}

Моя функция отображения производит Vector, которая вызвала бы вложенность (т. е. Vector(Vector(1), Vector(2), Vector(3), Vector(4))), если бы я использовал map из-за упаковки контейнера. Однако flatMap удалит эту вложенность и расплющит ее. Это имеет смысл, когда есть гнездование двух одинаковых монад.

Однако я не понимаю, как использование flatMap с функцией отображения, которая возвращает Option, делает Vector[Option[Int]] Vector[Int]. Происходит ли какая-то трансформация (я никогда не видел этого раньше), может ли кто-то объяснить и, возможно, указать мне на некоторые ресурсы?

Большое спасибо

2 3

2 ответа:

Мы можем использовать reify, чтобы увидеть, что происходит:

scala> import reflect.runtime.universe._
import reflect.runtime.universe._

scala> val v = Vector(Some(1), Some(2), Some(3), None)
v: scala.collection.immutable.Vector[Option[Int]] = Vector(Some(1), Some(2), Some(3), None)

scala> reify { v.flatMap(x => x) }
res0: reflect.runtime.universe.Expr[scala.collection.immutable.Vector[Int]] =
    Expr[scala.collection.immutable.Vector[Int]]($read.v.flatMap(((x) =>
     Option.option2Iterable(x)))(Vector.canBuildFrom))

Это показывает нам, что он использует option2Iterable преобразование для преобразования Option в Iterable, и Iterable является подтипом типа GenTraversableOnce, который ожидает flatMap.

Функция f передается в пределах flatMap здесь:

Vector(Some(1), Some(2), Some(3), None).flatMap{
    n => n
}

- это функция A => GenTraversableOnce[B], описанная в реализации flatMap:

def flatMap[B, That](f : scala.Function1[A, GenTraversableOnce[B]])
                    (implicit bf : CanBuildFrom[Repr, B, That])
                    : That = ???

Функция, реализованная в вашем примере n => n:

(n: Option[Int]) => n
Где A - это Option[Int], а B - это Int.

Потому что CanBuildFrom определяется как trait CanBuildFrom[-From, -Elem, +To]:

  • From - это Repr, а в данном случае Vector
  • Elem is B so Int

Результат flatMap, следовательно, Vector[Int]