Ответ 1
Как объяснил @chi Scala flatMap
, более общий, чем Haskell >>=
. Полная подпись из документов Scala:
final def flatMap[B, That](f: (A) ⇒ GenTraversableOnce[B])(implicit bf: CanBuildFrom[List[A], B, That]): That
Это неявно не относится к этой конкретной проблеме, поэтому мы могли бы использовать более простое определение:
final def flatMap[B](f: (A) ⇒ GenTraversableOnce[B]): List[B]
Есть только одна проблема, Option
не является подклассом GenTraversableOnce
, здесь происходит неявное преобразование. Scala определяет неявное преобразование из Option
в Iterable
, которое является подклассом Traversable
который является подклассом GenTraversableOnce
.
implicit def option2Iterable[A](xo: Option[A]): Iterable[A]
Неявный определяется в объекте-компаньоне Option
.
Более простой способ увидеть неявное на работе - назначить Option
Iterable
val
:
scala> val i:Iterable[Int] = Some(1)
i: Iterable[Int] = List(1)
Scala использует некоторые правила по умолчанию, чтобы выбрать List
как реализацию Iterable
.
Тот факт, что вы можете комбинировать разные подтипы TraversableOnce
с операциями монады, поступает из implicit class
MonadOps
:
implicit class MonadOps[+A](trav: TraversableOnce[A]) {
def map[B](f: A => B): TraversableOnce[B] = trav.toIterator map f
def flatMap[B](f: A => GenTraversableOnce[B]): TraversableOnce[B] = trav.toIterator flatMap f
def withFilter(p: A => Boolean) = trav.toIterator filter p
def filter(p: A => Boolean): TraversableOnce[A] = withFilter(p)
}
Это увеличивает каждый TraversableOnce
с помощью приведенных выше методов. Подтипы могут свободно определять более эффективные версии там, они будут скрывать неявные определения. Это относится к List
.