Ok, I think I understand:
- In a where clause, it is currently not possible to include all generic versions of Optional<>
- But it is possible to include all implementers of a certain protocol
- So, as a workaround, the OptionalType protocol can be created, and Optional can be extended with it
- Now when including the OptionalType protocol in a where clause, all generic versions of Optional<> will be included (but other implemeters of that protocol too)
- As it is not guaranteed that an implemeter of OptionalType actually is an Optional<>, the method flatMap needs to be used, which will definitely return an optional "U?"
- In flatten, the flatMap function will move the return type from Generator.Element to Generator.Element.T?
- Then filter and map are used to filter out nils and unwrap the remaining Some values
- Generator.Element.T is provided as a typealias by OptionalType, which just makes the generic type of Optional<T> accessible
>> I don't like this particular implementation, since it handles the other plausible implementors of `OptionalType` incorrectly. If `Generator.Element` is anything other than `Optional<Generator.Element.T>`, then `{ $0 }` will be `Generator.Element -> Optional<Generator.Element>` instead of `Generator.Element -> Generator.Element`, i.e. it'll be equivalent to `Some` instead of `id`.
Could you give an example of a working implementation where `Generator.Element` is anything other than `Optional<Generator.Element.T>`? I tried but could not come up with one.
>> If you could impose the additional constraint that `Generator.Element == Optional<Generator.Element.T>`...
Seems not to work, the Playground crashes when I enter this.
>> Alternatively, you could have an `intoOptional` method in `OptionalType` which bypasses the need to supply a `Generator.Element -> Optional<Generator.Element.T>` function to `flatMap`.
That's a good idea, works. Here is the full code:
protocol OptionalType {
typealias T
func intoOptional() -> T?
}
extension Optional : OptionalType {
func intoOptional() -> T? {
return self.flatMap {$0}
}
}
extension SequenceType where Generator.Element: OptionalType {
func flatten() -> [Generator.Element.T] {
return self.map { $0.intoOptional() }
.filter { $0 != nil }
.map { $0! }
}
}
let mixed: [AnyObject?] = [1, "", nil, 3, nil, 4]
let nonnils = mixed.flatten() // 1, "", 3, 4