Why does "flatMap" work with sequences of Option type in Scala?
Asked Answered
S

1

6

I can't figure out how the Scala compiler figures out how to use flatMap with a sequence of Options.

If I use a flatMap on a sequence of sequences:

println(Seq(Seq(1), Seq()).flatMap(a => a)) // List(1)

it will concatenate all nested sequences

The same happens if I use it with a sequence of Options:

println(Seq(Some(1), None).flatMap(a => a)) // List(1)

So the flatMap treats Option as a collection in this case. The question is why does this work? The flatMap has the following definition:

def flatMap[B, That](f: A => GenTraversableOnce[B])(implicit bf: CanBuildFrom[Repr, B, That]): That

Meaning that it expects a function that returns an instance of GenTraversableOnce, but Option does not inherit GenTraversableOnce. It only inherits Product and Serializable, and Product inherits Equals.

How does Scala compiler can use the flatMap on the sequence of Options in this case?

Schoening answered 8/10, 2017 at 10:34 Comment(1)
To add to Grzegorzs answer, this also arises from the fact Option[A] is a monad, although this is blurred out due to the generic signature on options flatmap. The flatMap (otherwise named bind) on Option[A] should really be: def flatMap(f: A => Option[B]): Option[B], which is what you see in functional libraries such as scalaz and cats.Patsypatt
A
6

Your observation is right. In this case, if the compiler can't match the type, it looks for an implicit conversion and finds one in Option's companion object:

import scala.language.implicitConversions

/** 
    An implicit conversion that converts an option to an iterable value
*/

implicit def option2Iterable[A](xo: Option[A]): Iterable[A] = xo.toList

This makes it possible to treat Options as Iterables.


Also, your code can be simplified using flatten:

Seq(Some(1), None).flatten
Aquatic answered 8/10, 2017 at 10:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.