Skip to main content

Swift: What do I understand about flatMap? (updated 27 July 2015)


Sometimes you read a blogpost and it is only by responding to the blogpost that you come to an understanding of your own understanding. I've written a lot about fumbling with flatMap, but it wasn't until I read Natasha the Robot's recent post (and saw it evolve in response to comments) that I brought all those things together into a list of what I currently understand about flatMap. And once I'd noted down what I knew about flatMap, I suddenly became scared that I might forget what I currently know about flatMap, so I'm reproducing the comment I made here.

Comment

So far I've come to the following understandings:

1. it [i.e. flatMap] can be used to reduce an array of optionals to non-optionals, e.g. [String?] to [String], as you've done here [in the post]

2. it can reduce nested arrays into a single array, e.g. [[1,2,3],[4,5,6]] to [1,2,3,4,5,6]

3. it works at a level one deeper than map (as seen in point 2), which means that if you pass it an array that is not multidimensional then it works but you shouldn't do it

4. flatMap when applied to a Swift optional has special knowledge about the enum (or rather it has its own overloading) and sees more than just the enum. So if I were to use the Swift std Optional enum like so:
[Optional.Some("String"),Optional.None].flatMap{$0}
I'd get back an array containing ["String"]

But if I were to roll my own optional enum:
enum MyOptional {
case Some(T), None
}
and do the same thing
[MyOptional.Some("String"),MyOptional.None].flatMap{$0}
I'd get back exactly the same optional array as I started with. So if I wanted to replicate the flatMap behaviour of the std Optional enum I'd have to do something like this:
[MyOptional.Some("String"),MyOptional.None].reduce([String](), combine: {
switch $1 {
    case .Some (let s):
        return $0 + [s]
    case .None:
        return $0
    }
}
)
... and not use flatMap at all, because flatMap like map always needs one for one returned. And this is where I eventually get to the point I'm making, which is that this kind of special behaviour makes flatMap tricky to grasp.

5. Finally, I understand that I need to read more about flatMap.

Beyond the comment

Following my comment Natasha replied and this gave me a second chance to think about how I might summarise more succinctly what I'd written. The result was:
What I think it boils down to is that optionals are a special case: flatMap will reduce an array of optionals to an array of regular instances, and it's important to know this, but that use can be thought of separately to its day job which is as in point 2.
So for now that's my understanding of flatMap. No doubt if it changes again in the future once I've had further opportunities to hear people talk and to read people's writing on the subject then I'll post again but for now I'm almost comfortable with my understanding of flatMap. But feel free to shake me up if you have something to share on the subject.

Update: 27 July 2015

Discussion of flatMap continued on twitter and across Natasha's blog, and one of the most interesting observations was from Pietruszewski (@radexp), who's point was also echoed in blog comments:

Essentially what we have here is the basis of an analogy, that passing optionals through flatMap is like passing an empty array, i.e. it disappears.

Optionals are not arrays (with a single value or no value) they are enums of case Some or None, and it's important to remember this, but at the same time the analogy works based on the idea of emptiness: an array that has no values is empty (but it is still an array), an Optional enum of type None holds no associated value, unlike Some, and so can also be considered in comparison empty.

To me this is a poetic observation, but is this the logic that justifies flatMap's behaviour with optionals or simply an observation of its outcomes? Is computer science at the level of flatMap poetic? Or is this some anomaly? What some might (coming from other languages) call an abomination? I can't answer these questions since Swift has been my first contact with flatMap, but the voices tell me there is definitely more to be understood.

Recent further reading

I realise that discussion of flatMap in Swift isn't recent, and Rob Napier's handling of it sticks in my head for one. But here's some stuff from the last week or so to help you think some more about flatMap in the context of Swift 2.0:



Endorse on Coderwall

Comments