Why is flatMap on a Vector[Option[Int]] whose mapper function result is not a Vector[Option[Int]] valid?

Deadly 提交于 2019-12-13 12:10:24

问题


For example,

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

produces a Vector(1, 2, 3) instead of giving an error. As I have seen in other languages, flatMap is used when you have a mapper function that produces nesting so I would expect this to be a valid flatMap:

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

My mapper function produces a Vector which would cause nesting (i.e. Vector(Vector(1), Vector(2), Vector(3), Vector(4))) if I used a map due to the container wrapping. However, flatMap will remove this nesting and flatten it. This makes sense when there is nesting of two identical monads.

However, I do not understand how using a flatMap with a mapper function that returns an Option makes a Vector[Option[Int]] become a Vector[Int]. Is there some sort of transformation going on (I have never seen this before), could someone explain and perhaps point me to some resources?

Thank you very much


回答1:


we can use reify to see what is going on:

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))

This is showing us that it is using the option2Iterable conversion to convert the Option to Iterable, and Iterable is a subtype of the GenTraversableOnce type that flatMap is expecting.




回答2:


The function f passed within the flatMap here:

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

Is a function A => GenTraversableOnce[B] as described in the flatMap implementation:

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

The function implemented in your example n => n is:

(n: Option[Int]) => n

Where A is Option[Int] and B is Int.

Because CanBuildFrom is defined as trait CanBuildFrom[-From, -Elem, +To]:

  • From is Repr, and in this case Vector
  • Elem is B so Int

The result of flatMap is therefore Vector[Int]



来源:https://stackoverflow.com/questions/34735364/why-is-flatmap-on-a-vectoroptionint-whose-mapper-function-result-is-not-a-ve

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