[Swift]flatMap・compactMapの挙動はソースコードを読んで理解しよう〜型情報と実装から難関メソッドを突破する〜


## 動機

`flatMap`の振る舞いって難しいですよね...。特に`Array`の`flatMap`。
どのような値を返すのか突き止めるべく、あらゆるパターンの呼び出しを試して個別にその挙動を確認し、
自分独自の概念もこねくり回しながら、どうにか法則を抽出しようと試みる。
だけど、どうしてもその挙動を言葉に落とし込むことができなくて、涙で枕をぬらす夜が続きました。

ところがある日、そのソースコードを読んでみると、
あれだけ内部で複雑な動きをしているかに見えた`flatMap`の振る舞いが、
(`Array`の場合は)2つのオーバーロードと、意外なほど簡潔なコードだけで実現されていたことがわかったのです。
個別の現象からその内部構造を推測する`トップダウン型`だけではなく、ソースコードに当たってその振る舞いを読み解く`ボトムアップ型`のアプローチも取り入れた結果、
これらのメソッドの振る舞いを、より多角的に理解できた気がしました。

で、これらに関連して`compactMap`なるメソッドが導入された新しいSwiftも正式リリースされて間もないことですし、そちらの話題もちょっぴり絡めつつ、まとめてみました。

この記事を読むことで、
`Optional`だったり、複雑な`Array`オブジェクトに対する`map`・`flatMap`呼び出し、おまけに`compactMap`までも、その挙動が手に取るように把握できるようになります。
その結果、これらのメソッドに対する自信が深まり、Swiftがさらに楽しくなります。
他方、そもそも`map`や`flatMap`とは何か、Swiftではどのように呼び出すのか...などといった事柄は、他の方の優れた解説に多くを任せようと思います。
この記事では、実際のソースコードを参照しながら`flatMap`の挙動を解剖していくことで、
これまでとは別の角度からこのメソッドの理解を促進することに挑戦したいと思います。

`Array`の`flatMap`と`compactMap`が混在する世界線の話ができたら理想的なので、
よければSwift 4.1以降をご用意のうえ、お読みくださると嬉しいです。

## 環境

Xcode 9.3
Swift 4.1

## 用語・あるとよさげな知識

記事中で用いる用語の語義と、もし知っていればこの記事が遥かに読みやすくなると思われる知識について、あらかじめ共有させてください。

### レシーバ

メソッドを呼び出す主体となるオブジェクトのこと。
メソッド呼び出しの記法 `オブジェクト.メソッド()`の、**`.(ドット)`の左側**。

```swift
let str = "HELLO"
str.lowercased()       // レシーバは `str`であり、"HELLO"

let dog = Dog()
dog.bark()             // レシーバは `dog`であり、Dog

let array = [1,2,3,4,5]
array.map{ $0 * $0 }   // レシーバは `array`であり、[1,2,3,4,5]
```

### あるとよさげな知識

[SwiftOptional四方山話](https://qiita.com/tarunon/items/844958accc4391097d97)、[
理論から入門するswift/lib/Sema - わいわいswiftc #1](https://speakerdeck.com/ukitaka/sema-waiwaiswiftc-number-1)などにあるように、

**オプショナル型とその非オプショナル型の間には、サブタイプ関係がある**`(T is T?)`

```swift
// T is T?

let optionalInt: Int? = 1  // `T?`型の変数に、`T`型のオブジェクトを代入できている
```

また、[Swiftの型の深淵をのぞく](https://qiita.com/koher/items/972ab84283b2a0d3ce1b)などにあるように、

**オプショナル型を戻り値にした関数オブジェクトとその非オプショナル型を戻り値にした関数オブジェクトの間には、サブタイプ関係がある**`(() -> T is () -> T?)`

```swift
// () -> T is () -> T?

func bar() -> Int { return 1 }
let barOptional: () -> Int? = bar // `() -> Int?`型の変数に、`() -> Int` 型の関数オブジェクトを代入できている
```

ということを知っていると、特に`Optional#map`、`Optional#flatMap`周りの説明などが読みやすくなると思います。

もうひとつ、[SwiftのOptional型を極める](https://qiita.com/koher/items/c6f446bad54442a28bf4#optional%E3%81%AF%E7%AE%B1%E3%81%A8%E8%80%83%E3%81%88%E3%82%8B)の中などで用いられている、「オプショナルとは箱である」というアナロジーを、この記事を通して借用しています。もしリンク先をまだ読んだことがない場合、ぜひ読んでみてください。

またこの記事全編に渡り、上記の記事を参照いたしました。

## Optional#flatMap(_:)の挙動を追う

標準ライブラリで定義された型のうち、`flatMap`を持つ型はいくつかあると思いますが、
実際の開発などで最もよく使うものは、`Optional`と`Array`のそれではないかと思います。
そのため、本記事ではこの2つの型に属する`flatMap`に絞って書いていきます。

では、まずは`Optional`における`flatMap`から。
`Array`が持つ`flatMap`に比べると複雑度は低いと思われますが、
それでも深い理解を求めるのであれば、丁寧に見ていく必要があると考えます。

### `map`・`flatMap`のきほん

そもそも`map`って、`flatMap`ってどんな感じの処理なんだ、ってお話を簡単に。

#### `map`

`map`･･･すなわち**マッピング**。
一般的なIT用語としてのマッピングなら、[^0]
> ある集合の個々の構成要素に対して、別の集合の要素を規則に従って機械的に対応付けたり割り当てたりすること。また、何かの分布や配置などを地図に重ね合わせて図示すること。

[^0]: [IT用語辞典](http://e-words.jp/w/%E3%83%9E%E3%83%83%E3%83%94%E3%83%B3%E3%82%B0.html)より引用いたしました。

とりわけ、プログラミングにおけるマッピングなら、

> あるオブジェクトをもとに、指定した変換ルールに基づき、新しいオブジェクトを生成すること。

こちらは引用というより、いま私が考えました。

変換ルールをクロージャとして指定して`map`に渡してあげることで、
その変換ルールに基づいて新たにオブジェクトを生成、返却してくれます。

たとえば、ある整数をもとに、その整数に1を足した整数を得たいなら、こんな感じ。

```swift
let num:    Int? = 42
let newNum: Int? = number.map{ $0 + 1 }
print(newNum)    // Optional("43")
```

<!--
こちらは、ある配列をもとに、各要素を自乗した配列を新たに作っています。

```swift
let array:    [Int] = [1, 2, 3, 4, 5]
let newArray: [Int] = array.map{ element in element * element }
print(newArray)  // [1, 4, 9, 16, 25]
```

結果が`Array`という「箱」で返ってきているのは、`Optional`の`map`の場合と同じですね。
-->

#### `flatMap`

さて、そんな感じで使える`map`メソッドなのですが、困ったこともあります。
例えばこんなケースだとどうでしょう。

標準ライブラリ`Int`には、文字列から整数を生成するイニシャライザが定義されています。[^1]

[^1]: ソースコードは[ここ](https://github.com/apple/swift/blob/master/stdlib/public/core/IntegerParsing.swift#L188)にあるようです。

```swift:IntegerParsing.swift
public init?(_ description: String) {
    self.init(description, radix: 10)
}
```

このイニシャライザはその定義に`init?`とあるように、
文字列から整数を生成できた場合、その整数を返しますが、
反対に生成できない場合、`nil`を返します(失敗可能イニシャライザ: `Failable Initializer`)。
つまり、このイニシャライザが返す値の型は、`Int?`になります。

```swift
let num1: Int? = Int("11")     // Optional(11)
let num2: Int? = Int("VA-11")  // nil

// オプショナル型を返す処理を、非オプショナル型の変数で受けることはできない
let num3: Int  = Int("11")     // コンパイルエラー
```

最後の行にあるように、

**オプショナル型を返す処理(メソッドや失敗可能イニシャライザ、他にも`Optional Chaining`など)の結果は、必ずオプショナル型の変数で受ける必要がある(非オプショナル型の変数で受けることはできない)**

という点は、一見当たり前のようで、何気にこのあと重要になるので、ぜひ知っておくとハッピーです。

(なお、そのようなルールになっている理由として、
もしオプショナル型を返す処理を非オプショナル型の変数で受けられるとしたら、
仮にその処理が`nil`を返した場合、本来`nil`を入れられない変数に`nil`を格納できてしまい、
null安全が崩壊する...といった説明ができるのでは、と思います。)

話を戻して、このイニシャライザを用いて`map`を呼び出してみましょう。

```swift
let a: String?     = "1"
let result: Int??  = a.map{ Int($0) }

print(result)      // Optional(Optional(1))
```

ありゃ。`map`を実行した結果、一重の`Optional`ではなく、二重の`Optional`で返ってきてしまいました。

このように、**`map`に渡したいクロージャが、その返り値にオプショナル型の値を返すクロージャ**だった場合、
`map`の代わりに`flatMap`を用いると、二重の箱をフラット（一重）にして結果を得られ、上手く対処できます。

```swift
let a: String?   = "1"
let result: Int? = a.flatMap{ Int($0) }
print(result)    // Optional(1)
```

`map`の処理に加えて、フラットにする(`Optional`という「箱」を、1個分ぺしゃんこにする)処理まで施してくれるのが`flatMap`なのですね。

### 実装を見る

ではその[実装](https://github.com/apple/swift/blob/master/stdlib/public/core/Optional.swift#L193-L202)を見てみましょう。
また、`Optional`の`flatMap`は`map`と対称性があり、比較しながら見ていくといっそう理解しやすくなるため、こちらも合わせて引用します(必要な箇所を抽出・編集しています)。

```swift:Optional.swift
public enum Optional<Wrapped> {
    case none
    case some(Wrapped)
    
    public func map<U>(
        _ transform: (Wrapped) throws -> U  // ※1 ここ同士が違う
        ) rethrows -> U? {
        switch self {
        case .some(let y):
            return .some(try transform(y))  // ※2 ここ同士も違う
        case .none:
            return .none
        }
    }
    
    public func flatMap<U>(
        _ transform: (Wrapped) throws -> U?  // ※1 ここ同士が違う
        ) rethrows -> U? {
        switch self {
        case .some(let y):
            return try transform(y)  // ※2 ここ同士も違う
        case .none:
            return .none
        }
    }
}
```

`map`と`flatMap`、交互ににらめっこしていると、

- 引数のクロージャの返り値 (※1)
- switch-case文の`case .some(let y)`内、return している箇所 (※2) **← 特に注目**

だけが少し異なり、それ以外は全く同じつくりであることがわかります。

シグネチャこそ2つのジェネリクス型(`Optional`に付随するジェネリクス型`Wrapped`と、メソッド内で使われるジェネリクス型`U`)が絡み、とっつきにくいのは確かなのですが、
より着目すべきはその本体(`{ }`の中身)であり、そこでなされている処理は意外なほどシンプルであることが見て取れます。

ではその`flatMap`の処理の中身を見てみましょう。

```swift:再掲
func flatMap<U>(
    _ transform: (Wrapped) throws -> U?
    ) rethrows -> U? {
    switch self {
    case .some(let y):
        return try transform(y)
    case .none:
        return .none
    }
}
```

> `flatMap`を呼び出した主体(レシーバ)の値が`nil`かどうかを判定し(`switch self`)、
> もし`nil`であれば、`nil`を返す。
> 一方`nil`でなければ、値バインディングパターン`(value-binding pattern)`のパターンマッチを用い(`case .some(let y)`)、
> 列挙体`Optional`のアソシエイト値として設定されている値(＝**「オプショナルという箱の中身」**)を取り出して(`let y`)、その値を引数で渡されたクロージャに適用する(`try transform(y)`)。
> 最後に、クロージャの実行結果を`flatMap`の結果として返す。

また、`map`は処理のほぼすべてが`flatMap`と同じなのですが、
1点だけ、クロージャの実行結果を**オプショナルでラップした上で返す**、という点だけが異なります。

```swift:再掲
func map<U>(
    _ transform: (Wrapped) throws -> U
    ) rethrows -> U? {
    switch self {
    case .some(let y):
        return .some(try transform(y))  // オプショナル型にラップした上で返す
    case .none:
        return .none
    }
}
```

こうして見ると、「`flatMap`がなんらかのフラットにする処理をしている」というよりも、
「`map`が処理のあと、あえて値をオプショナルに包んでいる(`.some(...)`)。`flatMap`の"flat"とは、その対としての"flat"。」と考えていたほうが、おさまりが良いかもしれません。
「値をオプショナルでラップする」という余計なひと手間をわざわざ施しているぶん、
なんだか`flatMap`よりも`map`のほうが特殊なメソッドのように感じられてきますね。
この動作を知るためには、その実装を覗くことなく到達するのはなかなか難しかったのでは...と思います。

### 注意点

さて、ここまであえて触れずにきたものの、気に掛けておかないといけない点があります。

上で見たように、`flatMap`の場合`map`と違って、
クロージャの実行結果がオプショナルに包まれることはありませんでした。

```swift:map
case .some(let y):
    return .some(try transform(y))  // こちらは、クロージャの実行結果をオプショナル型でラップしているが...
```

```swift:flatMap
...
case .some(let y):
    return try transform(y)  // こちらは、クロージャの実行結果を素直に返しているだけ
...
```

そのため、例えばこの`flatMap`全体の戻り値の型は、非オプショナルな型となってもよさそうなものです。

```swift
let a: Int? = 1
let result  = a.flatMap{ $0 + 1 }  // 戻り値の型は `Int`、値は2かな...🤔
```

ですが、実際はその戻り値の型は、オプショナル型である`Int?`になってしまいます。
また、これを無理やり`Int`型の変数で受けることはできません。

```swift
let a: Int? = 1
let result: Int? = a.flatMap{ $0 + 1 }  // 実際は、型は `Int?`、値はOptional(2)になってしまった😯

let result: Int  = a.flatMap{ $0 + 1 }  // これはコンパイルエラー
```

どうしてこのような結果になってしまうのでしょう。

もう一度`flatMap`のシグネチャに着目してみると、
引数として取るクロージャの定義に`_ transform: (Wrapped) throws -> U?`とありますね。

```swift
public func flatMap<U>(
        _ transform: (Wrapped) throws -> U?  // ← ここに注目
        ) rethrows -> U? {
    ...
}
```

クロージャ`transform`の戻り値は**「U?」**。
つまり、このクロージャを実行した結果返される値の型は、その定義にひきずられる形で、
オプショナル型であると解釈されてしまう(たとえ実際には「非」オプショナル型の値を返していたとしても)、というわけです。
そして`flatMap`が`return`するのはこのオプショナル型の値なので、そうなるとそれを受け取る変数もオプショナル型でなければいけないのですね。

```swift
let a: Int? = 1

// `flatMap`に渡されたクロージャが返している値の型は、
// { return $0 + 1 } ...すなわち実際には `Int` 型のオブジェクト(今回は2)なのだが、
// クロージャの戻り値が `U?` になっているせいで、
// このクロージャを実行したとき返される値の型は `Int?`であると解釈されてしまう
let result: Int? = a.flatMap{ $0 + 1 }
```

また、よしんば`transform`の戻り値が`「U?」`ではなく、`「U」`、つまり非オプショナル型だったと仮定してみましょう。

```swift
public func flatMap<U>(
        _ transform: (Wrapped) throws -> U  // ← 実際はこうではなく、あくまで仮定です
        ) rethrows -> U? {
    ...
}
```

ですが仮にそうだったとしても、`rethrows -> U?` とあるように、そもそも**`flatMap`全体の戻り値も `U?`、すなわちオプショナル型となっている**ため、結局はこの`flatMap`の実行結果はオプショナル型の変数で受け取らないといけません。

```swift
public func flatMap<U>(
        _ transform: (Wrapped) throws -> U  // ← この戻り値が仮に `U` だったとしても...
        ) rethrows -> U? {  // ← そもそも`flatMap`全体の戻り値が `U?`
    ...
}
```

これは、このようなコードを書くと確かめることができます。

```swift
// クロージャを受け取って実行し、その結果を返す関数
func myFunc<U>(
    _ completion: () throws -> U  // クロージャの戻り値の型は、非オプショナル型の `U` だが...
    ) rethrows -> U? {            // この関数全体の戻り値の型は、オプショナル型の `U?`。なので...
    return try completion()
}

// クロージャの戻り値が非オプショナル型だろうが、
// `myFunc`の戻り値が `U?` とオプショナル型になっているので、
// 結局このメソッドの結果は、オプショナル型の変数で受けないといけなくなる
let result1: Int? = myFunc{ return 1 }
// 当然非オプショナル型の変数で受けることはできず、コンパイルエラーになる
let result2: Int  = myFunc{ return 1 }  // error
```

そのため、どのみち`flatMap`実行結果の戻り値はオプショナル型と解釈される、というわけなのでした。

`flatMap`や`map`の結果が`Optional`で返ってくるのは、
簡単に言うと「`Optional`という箱の中身(値)に対して、それを箱から取り出すことなく(入れたまま)演算を行う」ことができると都合がよいから。
これにより、箱の中身(値)を外の世界に触れさせることなく、後続の処理につなげたりできるようになっています。
となると当然、返される値は`Optional`という箱に入ったまま、というわけですね。

### 挙動のまとめ

･･･存外長い説明となってしまいました。
いま一度、`Optional`の`flatMap`の挙動をまとめておきます。

**********
**Optional#flatMap**

・レシーバが`nil`ならば、`nil`を返す。
・レシーバが`nil`でないならば、レシーバの"箱の中身"に対して引数で渡したクロージャを適用し、
その結果を返す。
(・加えて、その型定義に引きずられる形で、その結果はオプショナル型の変数で受ける必要がある。)
**********

ついでに、`Optional`の`map`の挙動は、こう説明できます。

**********
**Optional#map**

・レシーバが`nil`ならば、`nil`を返す。
・レシーバが`nil`でないならば、レシーバの"箱の中身"に対して引数で渡したクロージャを適用し、
  結果をオプショナルに包んで、その結果を返す。
(・加えて、その型定義に引きずられる形で、その結果はオプショナル型の変数で受ける必要がある。
すなわち、クロージャ適用の結果得た値がオプショナル型であれば、二重のオプショナル型になる。)
**********

以上、ソースコードを参照しながら、`Optional`の`flatMap`(と、`map`)の仕組みについて考察しました。

### **(補足)** `Optional#map`・`Optional#flatMap`に関する補足

...と言いつつ、この項では`Optional#map`・`Optional#flatMap`にまつわる、
「さらに探求したかったので調べてみたけど、本筋からは外れる話題」について、補足としてまとめました。
次の`Array#flatMap(_:)の挙動を追う(その1)`までスキップでも一切支障ございません。

#### Q1. `(Wrapped) throws -> U?`に対し、なぜ`(Wrapped) -> U`を渡せるのか？

`Optional#flatMap`が引数として取るクロージャの型は `(Wrapped) -> U?` です。

```swift
public func flatMap<U>(
    _ transform: (Wrapped) throws -> U?  // クロージャ`transform`の型は `(Wrapped) -> U?`
    ) rethrows -> U? {
    ...
}
```

にもかかわらず、このようなコードが書けてしまうのです。

```swift:問題なくflatMapを呼び出せているが、本来であればmapで十分な場面
let a: Int? = 1

let result: Int? = a.flatMap{ $0 + 1 }  // `flatMap`に渡されたクロージャの返り値の型は`Int`
print(result)  // Optional(2)
```

`(Wrapped) -> U?`、つまりオプショナル型の返り値を返すクロージャを渡せ、と要求されているにもかかわらず、
`(Wrapped) -> U`、すなわち**非**オプショナル型の返り値を返すクロージャを渡せています。

`(Wrapped) -> U?`と`(Wrapped) -> U`、2つの型はそれぞれ別のものだというのに、
なぜこのようなコードが許されるのでしょうか？

<br>

どうやらSwiftにおいて、`() -> T`型の関数オブジェクトは、`() -> T?`型のサブタイプとして振る舞うことが可能なルールになっています。

***
() -> T is () -> T?
***

そのため、`() -> Int`型の関数オブジェクトを、`flatMap`へ渡せていた、というわけです。

```swift:問題なくflatMapを呼び出せているが、本来であればmapで十分な場面(再掲)
let a: Int? = 1

// `() -> Int` is `() -> Int?`なので、{ $0 + 1 } を`flatMap`に渡せていた！
let result: Int? = a.flatMap{ $0 + 1 }
```

前に見たように、`map`ではなくあえて`flatMap`を使うべき場面とは、**「クロージャの返り値の型がオプショナル型」**の場合です。
そのため、「クロージャの返り値の型がオプショナル型」**ではない**場合、`flatMap`は本来使えるべきではなく、理想的にはコンパイルが通らないような仕組みになっているのが望ましいですが...。
このルールのせいで、実際にはコンパイルが通り、実行できてしまいます。
このことが後で触れる`compactMap`が新設された遠因になっていたりもするようで、その経緯については[Swift 4.1で導入されたcompactMapとその背景について](https://qiita.com/amarillons/items/e897ca495470963249fe)、こちらの記事がProposalをベースに簡潔に解説されていて、たいへん勉強になりました。

なお、Swiftにおいて2つの型の間にサブタイプ関係がある場合に実現可能になることは、
本記事の終盤に、「サブタイプ関係がある場合にできること」という見出しで、補足としてまとめてあります。

#### Q2. `(Wrapped) -> U`に対し、なぜ`(Wrapped) -> U?`を渡せる(ように見えてしまった)のか？

`Optional#map`が引数として取るクロージャの型は `(Wrapped) -> U` です。

```swift
public func map<U>(
    _ transform: (Wrapped) throws -> U  // クロージャ`transform`の型は `(Wrapped) -> U`
    ) rethrows -> U? {
    ...
}
```

にもかかわらず、このようなコードが書けてしまうのです。

```swift
let a: String? = "1"
let result     = a.map{ Int($0) } // ...これ、`map`に渡されたクロージャの型は `(Wrapped) -> U?`。なんで渡せるんだ...?🤨
```

これが許されるのはちょっと奇妙な気がします。
`Q1.`で既に見たように、引数の型 `(Wrapped) -> Int?` に対し `(Wrapped) -> Int` を渡せるのはわかりました。
が、ここで起こっていることはその反対で、引数の型 `(Wrapped) -> Int` に対して、 `(Wrapped) -> Int?` のクロージャを渡せているかのように見えます。
ある2つの型がサブタイプ関係にある場合において、サブタイプになっている型に対しスーパータイプの型を渡すことは、本来できないはずなのでは...？
なぜこのようなコードが許されるのでしょうか？

...結論から言えば、当然私の考え方が間違っていたのです。
私の思考の誤ちを開陳させていただきたく思います。

<!--
`map`からは一瞬離れて、スーパータイプ `() -> Int?`、サブタイプ `() -> Int` というサブタイプ関係を考えてみましょう(∵ `if T is T? then () -> T is () -> T?`)。
この例のように、(`U`のようなジェネリクス型ではなく) `Int` のような一般的な型であれば、
引数の型 `() -> Int` に対して、 `() -> Int?`型のクロージャを渡すことはできません。
ここまでの考えは合っていました。

```swift
func myFunc(_ completion: () -> Int) -> Int {
    return completion()
}

// `() -> Int` に対し、`() -> Int?` のクロージャは渡せない
myFunc{ Optional.some(1) }  // コンパイルエラー
```
-->

今回のミソは、クロージャの戻り値が( `Int` のような一般的な型ではなく)`U` というジェネリクス型であり、コンパイル時に具体的な型に置き換えられる、という点にありました。

上で見たように、今回`map`に渡されたクロージャの型は`(String) -> Int?` です。

```swift
let a: String? = "1"
let result     = a.map{ Int($0) }  // クロージャの型は`(String) -> Int?`
```

するとその結果、`map`が持つ型パラメータ `U` が `Int?` に決定(特殊化)されることになります
(`map`のシグネチャに出現する`U`の箇所に着目して型パズルを解くと、論理的に`Int?`に定まることがわかります)。
そのときの状態はこうなります。

```swift:`map`が持つ型パラメータ`U`が特殊化された後の、今回の`map`の状態
// もともと`U`があった場所を`Int?`で置換すると、こうなる。
// 論旨とは全く関係ないが、`Wrapped`も`String`で特殊化された。
public func map<Int?>(
    _ transform: (String) throws -> Int?
    ) rethrows -> Int?? {
      ...
}
```

クロージャ`transform`が返す値の型は`Int?`、実際のコードで`map`に渡されたクロージャが返す値の型も`Int?`。(`Int($0)`)
よって、サブタイピング関係がどうのなんて話は初めから存在せず、`map`に渡されるクロージャにおいて型の整合性は保たれていたので、問題なくコンパイルできていた、というわけだったんですね。

**「クロージャが返す値の型は `U` って書いてあって、`U?` のように`?`が付いていないのだから、このジェネリクス型は絶対にオプショナル型にはならない！」**と思い込んでしまったが故に陥ったミスでした。
また、`U?` = `Optional<U>` という定義を柔軟に取り出せなかったことも、ドツボにはまっていった原因でした。
ここまでで判明したように、実際にはジェネリクス型に`?`が付いていなくても、それがオプショナル型で特殊化されることはありえます。
今回`U`が特殊化された型は`Int`ではなく、`Int?(Optional<Int>)`だったのです。

#### Q3. `U?` を返すメソッドで、なぜ `U??` を返せる(ように見えてしまった)のか？

`Q2.`の問題を考えていた際、同時に陥っていた問題がこちらです。
こちらも`Q2.`の解決と同時に解決しましたが、また忘れないように、文章にして残しておきます。

`Optional#map`が返す値の型は `U?` です。

```swift
public func map<U>(
    _ transform: (Wrapped) throws -> U
    ) rethrows -> U? {  // `map`が返す値の型は `U?`
    ...
}
```

にもかかわらず、このようなコードが書けてしまうのです。

```swift
let a: String?    = "1"
// `map`が返す値の型は`Int??`. 
// これって`map`の返す値の型は`U?`ということを考えると許容されないのでは...?🤨
let result: Int?? = a.map{ Int($0) }

print(result)  //  Optional(Optional(1))
```

`map`の戻り値の型 `U?` にもかかわらず、`Int??` という二重のオプショナルの値を返せている?
通常のサブタイプ関係を鑑みるなら、戻り値 `U??` に対し、実際には`U?`を返せるのはOKだけど、ここではその逆が成立している。
これはおかしいのではないか？と考えてしまいました。

...この勘違いも、`Q2.`の疑問が解けたと同時に払拭できました。

今回の場合、`map`が持つジェネリクス型 `U` が、`Int?` で解決(特殊化)されているので、`map`はこうなっていたのでした(上記コードの再掲)。

```swift:`map`が持つ型パラメータ`U`が特殊化された後の、今回のmapの状態(再掲)
// もともと`U`があった場所を`Int?`で置換すると、こうなる。
public func map<Int?>(
    _ transform: (String) throws -> Int?
    ) rethrows -> Int?? {
    ...
}
```

`map`の戻り値の型は`Int??`、実際の呼び出しの結果も `Int??`。
型の整合性はなんの問題もなく保たれていましたね。

```swift
let a: String?    = "1"
let result: Int?? = a.map{ Int($0) }  // 私の勘違い。実際は型の整合性は保たれていた😅

print(result)  //  Optional(Optional(1))
```

`Q2`・`Q3`の教訓として、**ジェネリクス型は当然`Optional<Wrapped>`型としても特殊化される場合がある。シグネチャの`?`の有無だけに捕らわれるな！**と自身に言い聞かせておきます。これでもう間違えるまい。

<!--
https://www.slideshare.net/ksc1213/swiftmonad
-->

## Array#flatMap(_:)の挙動を追う(その1)

本当はこちらが本日のメインディッシュです。
`Optional`に続き、`Array`の`flatMap`についてもその挙動を追っていきます。

### 実装を見る

さっそく[ソースコード](https://github.com/apple/swift/blob/master/stdlib/public/core/SequenceAlgorithms.swift#L662-L664)を確認してみましょう。[^2]
`Array`の`flatMap`は`Array`に直接書かれているのではなく、`Sequence`のプロトコル拡張として定義されているようです。
(必要な箇所を抽出・編集しています。)

```swift:SequenceAlgorithms.swift(4.1)
extension Sequence {
    ...
    public func flatMap<SegmentOfResult : Sequence>(
        _ transform: (Element) throws -> SegmentOfResult
        ) rethrows -> [SegmentOfResult.Element] {
        var result: [SegmentOfResult.Element] = []
        for element in self {
            result.append(contentsOf: try transform(element))
        }
        return result
    }
    ...
}

extension Sequence {
    ...
    // @available(swift, deprecated: 4.1, renamed: "compactMap(_:)",
    // message: "Please use compactMap(_:) for the case where closure returns an optional value")

    public func flatMap<ElementOfResult>(
        _ transform: (Element) throws -> ElementOfResult?
        ) rethrows -> [ElementOfResult] {
        return try _compactMap(transform)
    }
    ...
}
```

[^2]: なお、`Array#map`に関してはこの記事では取り扱いません。思いのほか長尺になってしまったものの`Optional#map`についてこれまで言及してきたのも、元を辿れば`Optional#flatMap`をより理解したいと思ったが故でした。決して[`Array#map`の実装](https://github.com/apple/swift/blob/master/stdlib/public/core/Sequence.swift#L820-L838)の意図を把握しきれなかったので取り上げることを放棄したといった話ではないと思います。それはさておいても、やはり`Array`の実装についても徐々に知識を深めていかないとなと考えています。

ここからわかるように、Arrayの`flatMap`には2種類が存在し、
その呼び出され方によって、どちらが使われるかが決定される、というわけだったのですね。

`flatMap`の呼び出し方によって、使われている`flatMap`の種類がそもそも違っていたため、
自分にとってその挙動を見抜くことが困難を極めていたのも、1つにはこの点が原因だったのでした。

どのような場合に、どちらの`flatMap`が呼ばれるのか？
その決定方法については後で改めて触れるとして、
まずは前者の**`flatMap<SegmentOfResult : Sequence>`**の挙動を追ってみたいと思います。

```swift:flatMap・その1
public func flatMap<SegmentOfResult : Sequence>(
    _ transform: (Element) throws -> SegmentOfResult
    ) rethrows -> [SegmentOfResult.Element] {
    var result: [SegmentOfResult.Element] = []
    for element in self {
        result.append(contentsOf: try transform(element))
    }
    return result
}
```

`Optional#flatMap`と同様、こちらもシグネチャの圧がやや強めですが、
そちらは一旦無視で実装のみに着目すると、その中身はわずか5行、かつその意図は非常に明確です。
あれだけクールなメソッドがたった5行で実装されていたなんて･･･ますますクールだ。

```swift:中身だけに着目すると...
public func flatMap<SegmentOfResult : Sequence>( ... ) {
    // その中身は、たった5行だけ
    var result: [SegmentOfResult.Element] = []
    for element in self {
        result.append(contentsOf: try transform(element))
    }
    return result
}
```

その中身について読み解いていきましょう。

> 配列の各要素を取り出して(`for element in self`)、引数で渡されたクロージャに適用し(`try transform(element)`)、その結果を一時変数に格納する(`result.append(...)`)。
> これをすべての要素に対して繰り返し、最後にその一時変数(新しい配列)を返す。

関数型プログラミングの香りを併せ持つとも称されるであろうこのメソッドですが、
その内部をひも解いていけば、実はバリバリ手続き型チックな記述で構成されていたこともわかりますね。

以下の例は、2次元配列(`[[Int]]`)をもとに、その中の要素(`[Int]`)をフラットにした新しい配列を返しています。

```swift
let result = [[1,2,3],[4,5]].flatMap{ $0 }

print(result)  // [1,2,3,4,5]
```

以降、当記事ではこの`flatMap`を、便宜上**「A) 配列をフラットにする`flatMap`」**と呼びます。

#### フラットにするのは`append(contentsOf:)`の仕事

さて、この`flatMap`はその内部で`append(contentsOf:)`というメソッドを使用していたのでした。

```swift:再掲
func flatMap<SegmentOfResult : Sequence>(
    _ transform: (Element) throws -> SegmentOfResult
    ) rethrows -> [SegmentOfResult.Element] {
    var result: [SegmentOfResult.Element] = []
    for element in self {
        result.append(contentsOf: try transform(element)) // ←ここ
    }
    return result
}
```

`append(contentsOf:)`は配列を引数に取り、その要素をレシーバに追加するメソッドです。[^4]
ここでなにげに重要なのが、`append(contentsOf:)`の引数として渡された配列は、レシーバにそのまま加わるのではなく、
**(配列という)その「箱」がつぶされた上で**加わる、という点です。

[^4]: ソースコードは[ここ](https://github.com/apple/swift/blob/master/stdlib/public/core/Arrays.swift.gyb#L1447-L1474)にあるようです。

```swift:
var array = [1,2,3]
array.append(contentsOf: [4,5])

// [1,2,3,[4,5]] ではなく、[4,5]を格納する箱がつぶされ(フラットにされ)た上で、レシーバに追加される
print(array)  // [1,2,3,4,5] 
```

ひるがえって、このような`flatMap`呼び出しを追ってみると･･･

```swift
let array  = [[1,2,3],[4,5]]      // このような二次元配列があったとき･･･
let result = array.flatMap{ $0 }  // それをそのままフラットにした新しい値を得たい

print(result)  // ???
```

レシーバ`array`の要素は`[1,2,3]`と`[4,5]`の2つなので、`flatMap`内部のforループは2回転。
1回転めが終わった時点の状態をトレースすると、
`append(contentsOf:)`の働きにより、内部の一時変数`result`はこんな感じで･･･

```swift:`flatMap`内部
func flatMap() {
    var result: [SegmentOfResult.Element]  // [1,2,3] 
    for element in self {                        
        result.append(contentsOf: ...)
    }
    ...
}
```

2回転めが終わった時点だと、こんな感じ。

```swift:`flatMap`内部
func flatMap() {
    var result: [SegmentOfResult.Element]  // [1,2,3,4,5] 
    for element in self {
        result.append(contentsOf: ...)
    }
    ...
}
```

よって、最終的な結果はこうなります。

```swift
let array  = [[1,2,3],[4,5]]      
let result = array.flatMap{ $0 }

print(result)  // [1,2,3,4,5]
```

つまり、こちらの`flatMap`が持つ「要素をフラットにした上で結果を返す」という性質は、
この**`append(contentsOf:)`**こそが担っていた、というわけですね。

`Array#append`には、`append(contentsOf:)`に加え、`append(_:)`という同名のメソッドが存在します。[^5]
そしてこちらの`append(_:)`には、引数に取った配列をフラットにした上でレシーバに加えるという機能はありません。

[^5]: ソースコードは[ここ](https://github.com/apple/swift/blob/master/stdlib/public/core/Arrays.swift.gyb#L1424-L1429)にあるようです。

```swift
var array = [[1,2,3]]
array.append([4,5]) // `append(contentsOf:)`ではなく、`append(_:)`を呼ぶ

print(array)  // [[1,2,3],4,5] ではなく、[[1,2,3], [4,5]]
```

後述するもう一方の`flatMap`が内部で使用しているのは、この`append(_:)`のほうです。
そしてこの違いこそが、2つの`flatMap`の挙動の違いを生んでいたのです。
また後ほど`Array#flatMap、Array#compactMapの注意点`で言及します。

### 注意点

後述したいと思います。

### 挙動のまとめ

改めて、こちらの`flatMap`の挙動をまとめます。

**********
**Array#flatMap`<SegmentOfResult:Sequence`>**

配列の各要素を取り出して、引数で渡されたクロージャに適用し、その結果を一時変数に格納する。
これをすべての要素に対して繰り返し、最後にその一時変数(新しい配列)を返す。
**********

## Array#flatMap(_:)の挙動を追う(その2)

さて、`Array`が持つ`flatMap`は、同名で別のものがありました。
なので、次はそちらの**`flatMap<ElementOfResult>`**の挙動を追ってみたいと思います。
(あらかじめ言ってしまうと、Swift 4.1で`compactMap`にリネームされた`flatMap`のことです。)

### 実装を見る

```swift:flatMap・その2
// @available(swift, deprecated: 4.1, renamed: "compactMap(_:)",
// message: "Please use compactMap(_:) for the case where closure returns an optional value")
public func flatMap<ElementOfResult>(
    _ transform: (Element) throws -> ElementOfResult?
    ) rethrows -> [ElementOfResult] {
    return try _compactMap(transform)
}
```

中身はたった1行、`(アンダーバー)compactMap`という別のメソッドに、その仕事を完全に横流ししています。
気を取り直して、`(アンダーバー)compactMap`の定義を見てみると...

```swift:_compactMap
func _compactMap<ElementOfResult>(
    _ transform: (Element) throws -> ElementOfResult?
    ) rethrows -> [ElementOfResult] {
    var result: [ElementOfResult] = []
    for element in self {
        if let newElement = try transform(element) {
            result.append(newElement)
        }
    }
    return result
}
```

どうやらこちらが実質的な本体のようですね。
といっても、こちらも1つ前に見た「(A) フラットにする`flatMap`」と非常に似ています。

```swift
// 前回見たやつ
func flatMap<SegmentOfResult : Sequence>( ... ) {
    var result: [SegmentOfResult.Element] = []
    for element in self {
        result.append(contentsOf: try transform(element))
    }
    return result
}

// 今回のやつ
public func flatMap<ElementOfResult>( ... ) {
    return try _compactMap(transform)
}

func _compactMap<ElementOfResult>( ... ) {
    var result: [ElementOfResult] = []
    for element in self {
        if let newElement = try transform(element) {
            result.append(newElement)
        }
    }
    return result
}
```

詳細を追ってみると、前回見た`flatMap`と異なる点は、

> ・`append`されるのは「クロージャを適用した結果得た値が`nil`でない場合のみ」という条件付きになったこと
> ・`append`の方法が`append(contentsOf:)`ではなく`append(_:)`になったこと

のみですね。とりあえず使ってみましょうか。

以下の例は、
「整数の文字列が格納された配列をもとに、それを整数に変換した新しい配列を取得したい。
ただし、整数への変換に失敗した場合は、その要素をドロップしたい(含めたくない)"。」
と考えた人が書いたコードとなります。

```swift
let result = ["1", "two", "3"].flatMap{ Int($0) }

print(result)  // [1, 3]
```

またこちらの例は、
「名字が格納された配列をもとに、それぞれの名字に"Kun(くん)"が付加された新しい配列を取得したい。
ただし、名字が特定の文字から始まっていた場合は、その要素をドロップしたい(含めたくない)"。」
と思い立ち、書いたコードとなります。

```swift
let result = ["Amemiya", "Sakamoto", "Kitagawa"].flatMap{
    guard  !$0.hasPrefix("A") else { return nil }
    return $0 + " Kun"
}

print(result)  // ["Sakamoto Kun", "Kitagawa Kun"] ← "A"から始まる名字はドロップされている
```

これらの例から察するに、こちらの`flatMap`は、
クロージャ実行の結果が`nil`になった場合、それをドロップした上で新しい配列を返す`flatMap`、といった感じになっています。
またこれを別の角度から見ると、特定の条件下でドロップしたい要素がある場合は、
**その条件のときに`nil`を返す**ようにクロージャ内を記述してあげるのが使い方のコツといえそうです。

以降、当記事ではこの`flatMap`を、便宜上**「B) `nil`をドロップする`flatMap`」**と呼称します。

また、上記で引用したコード定義内にあるコメントや、その定義の中身で誘導されるように、
こちらの`flatMap`は、Swift 4.1で非推奨となり、`compactMap`にリネームされました。
"compact"とはすなわち、`nil`をドロップすることのようです。

### 注意点

後述したいと思います。

### 挙動のまとめ

というわけで、こちらの`flatMap`(`compactMap`)の挙動をまとめます。

**********
**Array#flatMap`<ElementOfResult`> (`compactMap`)**

配列の各要素を取り出して、引数で渡されたクロージャに適用する。
その結果が`nil`ではなかった場合に限り、その結果を一時変数に格納する。
(逆に言うと、結果が`nil`だった場合、これはドロップされる。ここがミソ)
これをすべての要素に対して繰り返し、最後にその一時変数(新しい配列)を返す。
**********

## `Array#flatMap`、`Array#compactMap`の注意点

### A) 配列をフラットにする`flatMap`の注意点

・「A) 配列をフラットにする`flatMap`」は、要素の要素が`nil`だった場合、それをドロップしてくれるわけではありません。
「(B)」の方の挙動が頭に残っている場合、それにひきずられないようご注意。

```swift
// (A)
let result = [[1, nil], [3]].flatMap{ $0 }
print(result)  // [Optional(1), nil, Optional(3)] ← `nil`がドロップされていない
```

### B) `nil`をドロップする`flatMap`(=`compactMap`)の注意点

・また反対に、「(B) nilをドロップする`flatMap`(= `compactMap`)」には、
「A) 配列をフラットにする`flatMap`」が持つ、**要素をフラットにした上で返す** という性質は持ち合わせていません。
「(A)」の方の挙動が頭に残っている場合、それにひきずられないようご注意。

```swift
// (B)
let result = [1, 2, [3]].compactMap{ $0 }
print(result)  // [1,2,[3]] ← [3] という「箱」が、フラットになっていない
```

こちらについては前に触れたように、`Array#append`はオーバーロードによって2種類が存在し、それぞれその挙動が違うから、ですね。
(A) の`flatMap`が内部で使用している`append(contentsOf:)`は、引数の値を**フラットにした上で**内部の一時変数に追加するのに対し、
(B) の`flatMap`(=`compactMap`)が内部で使用している`append(_:)`には、そのような効果はないのでした。

というわけで、ここまでソースコードを読んできた私たちにとっては、これらの挙動も実は知っての通りでしたね。
(ウソです。私はこの点しこたま混乱し倒した上、この先また忘れそうだから私のために書きました)

## どのような場合に、どちらの`flatMap`が呼ばれるのか

`Array`オブジェクトに対し`flatMap`を呼び出した際、どちらの`flatMap`が呼び出されるのか、
その決定方法を考察してみましょう。
(`Xcode`のサポートを受けられるため、開発中これらの事柄に思考を巡らす必要は一切ありません。)

### 「A) 配列をフラットにする`flatMap`」に決定されるための条件

まず、「A) 配列をフラットにする`flatMap`」になるための条件から考えてみましょう。
その定義に型パラメータ<`SegmentOfResult : Sequence`> とあるので、これがキーになってきそうです。

```swift
func flatMap<SegmentOfResult : Sequence>(  ← ここ
    _ transform: (Element) throws -> SegmentOfResult
    ) rethrows -> [SegmentOfResult.Element] {
    ...
}
```

まず、`SegmentOfResult : Sequence` なので、`SegmentOfResult`になる型が`Sequence`に適合していないといけないことが確定します。
それに加え、この型パラメータがどこで出現してどう使われているのか、定義とにらめっこしてみると、
`flatMap`が取るクロージャ`transform`の返り値に、`SegmentOfResult` が出現していることがわかります。

```swift
func flatMap<SegmentOfResult : Sequence>(
    _ transform: (Element) throws -> SegmentOfResult  ← ここ
    ) rethrows -> [SegmentOfResult.Element] {
    ...
}
```

この2つを組み合わせて考えると、
**`flatMap`が取るクロージャの戻り値が`Sequence`に適合している場合**、
こちらの「A) 配列をフラットにする`flatMap`」に決定する、ということになりますね。

例えば、これなんかがそうです。[^6]

```swift
let numbers    = [1, 2, 3]
let flatMapped = numbers.flatMap { Array(repeating: $0, count: $0) }

print(flatMapped)  // [1, 2, 2, 3, 3, 3]
```

クロージャの戻り値の型は`Array`、とうぜん`Sequence`に適合してるので、
「A) 配列をフラットにする`flatMap`」のほうが呼び出されています。
(コードを見ただけでは確証が持てない場合でも、
`alt`+クリックでヘルプを表示し、どちらが呼び出されているか確認すれば大丈夫です。)

[^6]: この`flatMap`の使用例はソースコード内の文書化コメントからただパクってきたものなのですが、この記事を書いている際、ふとそのヘルプメッセージ(コメント)が古いまま残っていたことに気づきました。「なぜ`flatMap`ともあろうメジャーなAPIのコメントが2年前から放置されているんや...」と訝しみながらもPRを出してみたところ、12時間ほどでマージされてしまい(ただのコメント修正だからここまで短かったに違いない)、図らずとも自身初めてのSwiftへのコミット体験となりました。また、どう見積もっても書くのに1分とかからなかった2行の修正コードが、結果としてこれまで書いてきた中で最もインパクトを持つコードになりました。Contributionなんて言うのも憚れるミクロな修正でしたが、当の本人にとってはありえん嬉しみが深かったです。世界で一番好きな技術のコミュニティに受容される、これほど自己承認欲が充足され、また幸せなことは他にありません。この気持ちを忘れずに、次こそはコアライブラリ、そして標準ライブラリ･･･と手を入れられる開発者になれるよう、成長していきたいと思います。

###「B) `nil`をドロップする`flatMap`(=`compactMap`)」に決定されるための条件

一方、「B) `nil`をドロップする`flatMap`(=`compactMap`)」になる場合ですが...こちらはここまで来たら簡単です。
すなわち、A)の場合と反対に、**`flatMap`(=`compactMap`)が取るクロージャの戻り値が`Sequence`に適合していない**場合、
こちらの`flatMap`(=`compactMap`)が呼ばれることになります。

例えば、これなんかがそうです。

```swift
// 'flatMap' is deprecated: Please use compactMap(_:) for the case where closure returns an optional value
let flatMapped = ["1", "two", "3"].flatMap{ Int($0) }
print(flatMapped)  // [1, 3]
```

クロージャの戻り値の型は`Int?`、`Sequence`には適合していません。
そのため A) ではなく、「B) `nil`をドロップする`flatMap`(=`compactMap`)」のほうが呼び出されています。

もちろんこの場合、`flatMap`じゃなくて`compactMap`を使え、と警告されます。
将来的にはエラーになりそうだし、素直に従っておきます。

```swift
let compactMapped = ["1", "two", "3"].compactMap{ Int($0) } // ←`compactMap`に変更
print(compactMapped)  // [1, 3] ← 結果はもちろん同じです
```

以上、どんな場合に、どちらの`flatMap`が使われるか、を考察してきました。
最初にお伝えしたように、通常こんなことを毎回考える必要は全くなくて、
上の例にあるように`compactMap`を使うべきシーンで`flatMap`と書いた場合、
`Xcode`が`compactMap`を使うように警告を出してくれて、簡単にリネームできるようになっています。

<!--
ここまで見てきたように、それなりに複雑な型の規律に支配されている`flatMap`事情ですが、
それをコンパイルする前の時点で判断したり、IDEサポートの恩恵に預かれるあたり、
静的型付けの長所ここにも見たり、といった感じでしょうか。
-->

## **(補足)** サブタイプ関係がある場合にできること

前項までで本筋の内容は終了しました。`おわりに`までスキップでも一切支障ございません。
また、この項は後日、独立した記事としてくくり出したいと思います。

Swiftにおいて、2つの型のあいだに**`サブタイプ関係`がある場合に可能になること**をまとめてみました。
それぞれの「できること」について、

A) 以下のような継承関係を持つ独自型 (`Dog is Animal`)

```swift
class Animal {}
class Dog: Animal {}

print(Dog() is Animal)  // true
```

と、

B) ある非オプショナル型は、そのオプショナル型のサブタイプ(`T is T?`)

```swift
print(1 is Int?)  // true
```

という、2つのサブタイプ関係を例にとって見ていきます。

**1: スーパータイプの変数に、サブタイプのインスタンスを代入できる**

```swift
// 【Animal - Dog】パターン
let animal: Animal    = Dog()

// 【T? - T】パターン
let optionalInt: Int? = 1
```

**2: 関数がスーパータイプの引数を要求するとき、サブタイプのインスタンスを渡せる**

```swift
// 【Animal - Dog】パターン
func takeAnimal(_ animal: Animal) { }
takeAnimal(Dog())

// 【T? - T】パターン
func takeOptional(_ optional: Int?) { }
takeOptional(1)
```

**3: 関数の戻り値の型がスーパータイプのとき、サブタイプのインスタンスを返せる**

```swift
// 【Animal - Dog】パターン
func getAnimal() -> Animal {
    // 関数の返り値は`Animal`だが、サブクラスである`Dog`オブジェクトを返せる
    return Dog()
}
// 関数が返した`Dog`オブジェクトは、代入時に関数の戻り値の型へ型強制(暗黙的なアップキャスト)される
let animal: Animal = getAnimal()
// 変数に格納されたオブジェクトの型は`Dog`なので、もちろんダウンキャストには成功する
print(animal as! Dog)  // 成功

//【T? - T】パターン
func getOptional() -> Int? {
    // 関数の返り値は`Optional<Int>`だが、サブタイプである`Int`オブジェクトを返せる
    return 1
}
// 関数が返した`Int`オブジェクトは、代入時に関数の戻り値の型へ型強制(暗黙的なアップキャスト)される
let optionalInt: Int? = getOptional()
// 変数に格納されたオブジェクトの型は`Int`なので、もちろんダウンキャストには成功する
print(optionalInt as! Int)  // 成功
```

**4: 親クラスのメソッドの「スーパータイプの戻り値」を、子クラスのメソッド定義内で「サブタイプの戻り値」を返すようにオーバーライドできる**

```swift
// 【Animal - Dog】パターン
class SuperClass1 {
    func foo() -> Animal   { return Animal() }
    var  bar: Animal       { return Animal() }
    var  baz: () -> Animal {
        return { return Animal() }
    }
}

class SubClass1: SuperClass1 {
    // サブタイプの戻り値を返すようにオーバーライドできる(Dog is Animal)
    override func foo() -> Dog { return Dog() }
    // コンピューテッドプロパティでも成立する
    override var bar: Dog { return Dog() }
    // もしや、と思ったら...こう書ける。マジかｗ
    override var baz: () -> Dog {
        return { return Dog() }
    }
}

// 【T? - T】パターン
class SuperClass2 {
    func foo() -> Int?   { return Optional.some(1) }
    var  bar: Int?       { return Optional.some(1) }
    var  baz: () -> Int? {
        return { return Optional.some(1) }
    }
}

class SubClass2: SuperClass2 {
    // サブクラスの型を返すようにオーバーライドできる(Int is Optional<Int>)
    override func foo() -> Int { return 1 }
    // コンピューテッドプロパティでも成立する
    override var bar: Int { return 1 }
    // もしや、と思ったら...こう書ける。マジかｗ
    override var baz: () -> Int {
        return { return 1 }
    }
}
```

また、もし2つの型の間にサブタイピング関係があるなら...

```
if T   is Optional<T>
if Dog is Animal
```
 
それらの型を戻り値に置いた関数オブジェクトにおいても、サブクラス関係が成立する、といえます。

```
then () -> T   is () -> Optional<T>
then () -> Dog is () -> Animal
```

よって、以下のようなコードが成立します。
(もしかすると「類型5」としてではなく「類型1や2や3の亜種」と考えた方が自然に感じられるかもしれません。)

**5-1: `() -> スーパータイプ`の変数に、`() -> サブタイプ`の関数オブジェクトを代入できる**
(類型1の亜種とも考えられる)

```swift
// 【Animal - Dog】パターン
func foo() -> Dog { return Dog() }
let fooAnimal: () -> Animal = foo  // `() -> Animal`型の変数に、`() -> Dog` 型の関数オブジェクトを代入できている

// 【T? - T】パターン
func bar() -> Int { return 1 }
let barOptional: () -> Int? = bar // `() -> Int?`型の変数に、`() -> Int` 型の関数オブジェクトを代入できている
```

**5-2: `() -> スーパータイプ`を要求する引数に対し、`() -> サブタイプ`の関数オブジェクトを渡せる**
(類型2の亜種とも考えられる)

```swift
// 【Animal - Dog】パターン
func takeClosure(_ completion: () -> Animal) { }

func getDog() -> Dog { return Dog() }
takeClosure(getDog)  // `() -> Animal` 型の引数に対し、`() -> Dog` の関数オブジェクトを渡せている

takeClosure{ Dog() }   // ↑の2行を手短に書くとこう。やってることは同じ

// 【T? - T】パターン
func takeClosure(_ completion: () -> Int?) { }

func getOne() -> Int { return 1 }
takeClosure(getOne)  // `() -> Int?` 型の引数に対し、`() -> Int` の関数オブジェクトを渡せている

takeClosure{ 1 }  // ↑の2行を手短に書くとこう。やってることは同じ
```

**5-3: `() -> スーパータイプ`の関数オブジェクトを返す関数で、`() -> サブタイプ`の関数オブジェクトを返せる**
(類型3の亜種とも考えられる)

```swift
// 【Animal - Dog】パターン
func returnClosure() -> () -> Animal {
    return { Dog() }  // `() -> Animal`の関数オブジェクトを返す関数で、`() -> Dog`の関数オブジェクトを返せている
}

// 【T? - T】パターン
func returnClosure() -> () -> Int? {
    return { 1 }  // `() -> Int?`の関数オブジェクトを返す関数で、`() -> Int`の関数オブジェクトを返せている
}
```

この他にもできることがあれば、ご教示いただけると嬉しいです。

## おわりに

さまざまな`flatMap`の実体に、そのソースコードを読むことで迫ってきました。
もしもこの先、`flatMap`が一見不可解な値を返してきた場面に遭遇したとしても、
ソースコードという「ここに立ち返れば大丈夫！」という道しるべを手にできたのは私にとって大きかったです。
そしてそれは、心の平穏ももたらしてくれるはずです。

一行一行、論理の整合性を踏みしめながら進んでいきたい私のような俗物にとって、型にうるさめのSwiftは本当にぴったりな言語だと感じています。
「この挙動はなぜ？」という事象に出くわしても、これまで集めてきた知識を組み合わせ、粘り強く考えていくことで解答にたどり着ける確率が非常に高いのは、Swiftの抗いがたい魅力です。

<!--
また、「Optionalの`flatMap`」と、これから登場する「Arrayの`flatMap`」は、**それぞれ別物**という考えでいた方が無難なのかな...と思っています。
「同じ名前のメソッドなのだから、OptionalだろうがArrayだろうが、その振る舞いについて統一的な説明ができるだろうがよ！」と思ったので、
さまざまなオブジェクトを用意して`flatMap`を呼びまくり、それを得んとトライしていたのですが、
ついにはそれを獲得することはできませんでした。

これまで見てきたように、
そもそもOptionalとArrayの`flatMap`は、それぞれ全く別な書き方で実装されていたのですから、今思えばそれも無理のないことでした。
Swiftなら、必ずや**統一的で美しい説明をもたらしてくれるようになっているに違いない**。
そんなドグマに囚われすぎていたが故の失態でした･･･
-->

`Array`の`flatMap`の一部が`compactMap`へと切り分けられ、ジェネリクスの機能も漸進していく中、残る関心事は･･･`flatMap`がプロトコル`Monad`で抽象されたり、そのために必要な記述力をSwiftが獲得するーそんな未来はいつの日か訪れるのでしょうか？
･･･それに思いを馳せるには、自分自身さらなる精進が必要なので、今日はこれにて。

## links

[mapとflatMapという便利メソッドを理解する](https://qiita.com/shimesaba/items/1a89cb5600454f91cc67)

<!--
[こちら](http://swiftlife.hatenablog.jp/entry/2016/01/05/142850)によると、

> flatten()が使用できるのは、CollectionType,SequenceType,LazyCollectionType,LazySequenceTypeの4種類です。
-->