Hola Habr!
Mi nombre es Alexander Zimin, soy desarrollador de iOS en Badoo. Esta es una traducción de un artículo de mi colega Schwib, en el que describió cómo era la función flatMap en Swift y por qué una de sus sobrecargas pasó a llamarse compactMap. El artículo es útil tanto para comprender los procesos que ocurren en 
el repositorio Swift y 
su evolución , como para el desarrollo general.

En la programación funcional, hay una definición clara de lo que 
flatMap función 
flatMap . El método 
flatMap toma una lista y una función de transformación (que para cada transformación espera obtener cero o más valores), la aplica a cada elemento de la lista y crea una lista única (aplanada). Este comportamiento es diferente de la función de 
map simple, que aplica una transformación a cada valor y espera obtener solo un valor para cada transformación.

Para varias versiones, Swift tiene un 
map y 
flatMap . Sin embargo, en 
Swift 4.1 ya no puede aplicar 
flatMap a una secuencia de valores y aún pasar un cierre que devuelve un valor opcional. Ahora hay un método 
compactMap para 
compactMap .
Al principio puede no ser tan fácil entender la esencia de la innovación. Si 
flatMap funcionó bien, ¿por qué introducir un método separado? Vamos a resolverlo.
La biblioteca estándar de Swift anterior a la versión 4.1 proporcionaba tres implementaciones de sobrecargas para 
flatMap :
 1. Sequence.flatMap<S>(_: (Element) -> S) -> [S.Element],  S : Sequence 2. Optional.flatMap<U>(_: (Wrapped) -> U?) -> U? 3. Sequence.flatMap<U>(_: (Element) -> U?) -> [U] 
Veamos las tres opciones y veamos qué hacen.
Sequence.flatMap <S> (_: (Elemento) -> S) -> [S.Element], donde S: Secuencia
La primera sobrecarga es para secuencias en las que un cierre toma un elemento de esa secuencia y se convierte en otra secuencia.
flatMap todas estas secuencias transformadas en la secuencia final devuelta como resultado. Por ejemplo:
 let array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] let flattened = array.flatMap { $0 }  
Este es un gran ejemplo de cómo debería funcionar el método 
flatMap . Transformaremos (mapearemos) cada elemento de la lista fuente y crearemos una nueva secuencia. Gracias a 
flatMap resultado final es una estructura aplanada de secuencias transformadas.
Opcional.flatMap <U> (_: (Envuelto) -> U?) -> U?
La segunda sobrecarga es para tipos opcionales. Si el tipo opcional que está llamando tiene un valor, se llamará al cierre con el valor sin el contenedor opcional (valor sin envolver), y puede devolver el valor opcional convertido.
 let a: Int? = 2 let transformedA = a.flatMap { $0 * 2 }  
Sequence.flatMap <U> (_: (Elemento) -> U?) -> [U]
La tercera sobrecarga lo ayudará a comprender para qué 
compactMap . Esta versión se ve igual que la primera, pero hay una diferencia importante. En este caso, el cierre vuelve opcional. 
flatMap procesa, omitiendo los valores nulos devueltos e incluye todo el resto, en el resultado como valores sin un contenedor.
 let array = [1, 2, 3, 4, nil, 5, 6, nil, 7] let arrayWithoutNils = array.flatMap { $0 }  
Pero en este caso, no se realiza el pedido. Por lo tanto, esta versión de 
flatMap más cerca del 
map que la definición puramente funcional de 
flatMap . Y el problema con esta sobrecarga es que no puede usarlo correctamente donde el 
map funcionaría perfectamente.
 let array = [1, 2, 3, 4, 5, 6] let transformed = array.flatMap { $0 }  
Este uso de 
flatMap corresponde a la tercera sobrecarga, envolviendo implícitamente el valor convertido en opcional, y luego eliminando el contenedor para agregarlo al resultado. La situación se vuelve especialmente interesante si las conversiones de cadenas no se usan correctamente.
 struct Person { let name: String } let people = [Person(name: “Foo”), Person(name: “Bar”)] let names = array.flatMap { $0.name } 
En Swift antes de la versión 4.0, obtendríamos una conversión a 
[“Foo”, “Bar”] . Pero a partir de la versión 4.0, los valores de cadena implementan el protocolo Collection. Por lo tanto, nuestro uso de 
flatMap en este caso, en lugar de la tercera sobrecarga, corresponderá a la primera, y obtendremos un resultado "aplanado" de los valores convertidos: 
[“F”, “o”, “o”, “B”, “a”, “r”]Al llamar a 
flatMap no recibirá un error, ya que se permite su uso. Pero la lógica se romperá, porque el resultado es de tipo 
Array<Character>.Type , no el 
Array<String>.Type .
Conclusión
Para evitar el mal uso de 
flatMap , la tercera versión sobrecargada se ha eliminado de la nueva versión de Swift. Y para resolver el mismo problema (eliminar valores nulos) ahora necesita usar un método separado: 
compactMap .