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 MyOptionaland do the same thing{ case Some(T), None }
[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:
@natashatherobot
[[1], [2], [], [4]].flatMap { $0 }
vs
[1, 2, nil, 4].flatMap { $0 }
— Radek Pietruszewski (@radexp) July 25, 2015
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.
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.
@sketchyTech My suggestion is, to understand flatMap, don't start with Swift because it contains an overloaded can of inexplicable worms.
— Al Skipp (@al_skipp) July 26, 2015
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:
Map and FlatMap (Rui Peres)
Swift 2.0: Understanding flatMap (Natasha the Robot)
Changes to the Swift standard library in 2.0 betas 2..<5 (Airspeed Velocity)
Swift 2.0: Understanding flatMap (Natasha the Robot)
Changes to the Swift standard library in 2.0 betas 2..<5 (Airspeed Velocity)
Comments
Post a Comment