Wan ChengCheng
Wan ChengCheng

Reputation: 67

What's the magic behind this flatMap code?

I'm learning Scala and in the below code using flatMap (taken from filter with flatmap or collect)

I have

list flatMap {
    case st: String => Some(st)
    case _ => None
}

It works on List[Any] and yield List[String]

scala> List(1, "A") flatMap {
     | case st: String => Some(st)
     | case _  => None
     | }
res21: List[String] = List(A)

Now I'm confused about the types here. As I thought, flatMap works on some kinds of monad which works as a transformation from M[M[A]] -> M[A].

The code bellow is easy to understand,

def flatten(ls: List[Any]): List[Any] = ls flatMap {
    case ms: List[_] => flatten(ms)
    case e => List(e)
}

since both case return a List[Any], which is still the same type of ls: List[Any].

But why Some[String] and None are acceptable in the flatMap of a List[Any] ?

Besides, it seems like None is completely ignored rather then treated as a serious value ? I was thinking there maybe some kinds of compacting steps to get rid of such values, like:

[1,2,3].concat([,,2,2])
// => (6) [1, 2, 3, empty × 2, 2]
[1,2,3].concat([,,4]).filter(Boolean)
// => (4) [1,2,3,4]

Can someone explain these? Thanks!!!

Upvotes: 1

Views: 114

Answers (2)

Alexey Romanov
Alexey Romanov

Reputation: 170713

As I thought, flatMap works on some kinds of monad which works as a transformation from M[M[A]] -> M[A].

Scala flatMap is more general (which some people don't like).

If you look at documentation, it's enough for the function passed to List#flatMap to return GenTraversableOnce[SomeType], not List[SomeType]. And even though Option doesn't extend GenTraversableOnce, there is an implicit conversion between them which gets applied here.

Besides, it seems like None is completely ignored rather then treated as a serious value ?

None corresponds to an empty collection, Some(x) to a single-element collection. So you have e.g.

Some(1) ++ Some(2) ++ None ++ Some(3) ==
List(1) ++ List(2) ++ List() ++ List(3) ==
List(1,2,3)

Or, in your terms, you don't have [1,2,3,,,4] (which doesn't make sense), but [[1],[2],[3],[],[],[4]].

Upvotes: 4

Tim
Tim

Reputation: 27356

flatMap is not restricted to nested collections of the same type. The value returned by the function passed to flatMap can be any collection type. flatMap will take each element in that collection and append it to the result collection. Option[T] works like a collection of 0 or 1 elements, so flatMap works as it would with a List, Vector, Array or other collections.

However in this specific case you would actually use collect rather than flatMap:

list.collect{ case s: String => s }

Upvotes: 1

Related Questions