В чем магия этого кода flatMap? - PullRequest
0 голосов
/ 06 июля 2018

Я изучаю Scala и код ниже, используя flatMap (взято из фильтра с плоской картой или сбора )

У меня есть

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

Работает на List[Any] и дает List[String]

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

Теперь я запутался насчет types здесь. Как я и думал, flatMap работает на некоторых видах monad, который работает как преобразование из M[M[A]] -> M[A].

Код ниже легко понять,

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

, так как оба случая возвращают List[Any], который по-прежнему имеет тип ls: List[Any].

Но почему Some[String] и None допустимы в flatMap List[Any]?

Кроме того, похоже, что None полностью игнорируется, а не рассматривается как серьезное значение? Я думал, что, может быть, есть какие-то шаги сжатия, чтобы избавиться от таких значений, как:

[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]

Может кто-нибудь объяснить это? Спасибо !!!

Ответы [ 2 ]

0 голосов
/ 06 июля 2018

flatMap не ограничивается вложенными коллекциями одного типа. Значение, возвращаемое функцией, переданной flatMap, может быть любого типа коллекции. flatMap возьмет каждый элемент в этой коллекции и добавит его в коллекцию результатов. Option[T] работает как набор из 0 или 1 элементов, поэтому flatMap работает как с List, Vector, Array или другими коллекциями.

Однако в этом конкретном случае вы бы на самом деле использовали collect вместо flatMap:

list.collect{ case s: String => s }
0 голосов
/ 06 июля 2018

Как я и думал, flatMap работает с некоторыми видами монад, которые работают как преобразование из M [M [A]] -> M [A].

Scala flatMap является более общим (что не нравится некоторым людям).

Если вы посмотрите на документацию , достаточно, чтобы функция, переданная в List#flatMap, возвращала GenTraversableOnce[SomeType], а не List[SomeType]. И хотя Option не расширяет GenTraversableOnce, между ними существует неявное преобразование , которое применяется здесь.

Кроме того, похоже, что никто не полностью игнорируется, а не рассматривается как серьезное значение?

None соответствует пустой коллекции, Some(x) соответствует одноэлементной коллекции. Так у вас есть, например,

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

Или, по-вашему, у вас нет [1,2,3,,,4] (что не имеет смысла), но [[1],[2],[3],[],[],[4]].

...