SwiftのFunctional Programmingっぽい書き方を理解する

# はじまり

Swiftを勉強をする上で避けて通れない*Functional Programming*について`filter`や`reduce`を使ったり、作ったりして勉強してみます。※ おおよそ参考サイトから引用しているので分かりづらければ元サイトを見てください。

## 実施環境
* Xcode Version 7.2 (Playground)
* Swift version 2.1.1

# 配列をフィルタリングする

## 今までのやり方
1から10の数値から偶数のみ取り出した配列を生成したい場合、今まではこのような処理を行っていたと思います。

```swift
var evens = [Int]()
for number in 1...10 {
    if number % 2 == 0 {
        evens.append(number)
    }
}
print(evens) // [0, 2, 4, 6, 8, 10]
```

まず偶数の数値を格納する配列を用意して`for-in`で10回まわして、条件に当てはまる場合は用意した配列に追加する…

上記の方法は内部の構造が明示的ですがコードの再利用を行うとしたらコピペに頼るしかなくなります。

## Functionalなやり方

```swift
func isEven(number: Int) -> Bool {
    return number % 2 == 0
}
let evens = Array(1...10).filter(isEven)
print(evens) // [0, 2, 4, 6, 8, 10]
```

先ほどの条件処理部分を抜き出した`isEven`は偶数であれば`true`を返す単純な関数です。それを引数に渡しているのが肝です。

`filter`は**与えられた関数**が`true`を返す時だけ配列の中身を取り出し、新たな配列を返す関数です。

またこの引数として渡す関数はクロージャとしても宣言できます。

```swift
let evens = Array(1...10).filter { (number) -> Bool in
    return number % 2 == 0
}
print(evens) // [0, 2, 4, 6, 8, 10]
```

さらに戻り値の型推論で`-> Bool`が必要なく、クロージャは最後の値を戻り値としてを暗黙に返すので`return`が必要なく、引数も自動的に`$0, $1, ...`と連番が与えられるので`number in`も必要なくなります。

つまり残ったのはこれだけ、最近よく見る書き方になりました。

```swift
let evens = Array(1...10).filter { $0 % 2 == 0 }
print(evens) // [0, 2, 4, 6, 8, 10]
```

※しかし略した記法は可読性を下げる可能性が高く、好みが分かれるのでチームで開発する際にはコーディング規則に則って行いましょう。

話が少し逸れてしまいましたが、この関数を引数として受け取る関数は**高階関数**と言いい、*Functional Programming*の基本となります。またクロージャを使用することもできます。

## フィルターを自作する

Swiftの~~配列~~`CollectionType`(親は`SequenceType`)に準拠した型のインスタンスは上記`filter`の他に`map`、`SequenceType`であれば`reduce`など多くの*Functional*な関数を用意しています。その使い方を知りたい場合は下記リンクが分かりやすいのでオススメです。

[Swiftのmap, filter, reduce（などなど）はこんな時に使う！](http://qiita.com/mo_to_44/items/cf83b22cb34921580a52)

ではその`filter`がどのように実装しているのか理解するために、自作の高階関数を定義してみましょう。

```swift
func goodFilter<T>(source: [T], predicate:(T) -> Bool) -> [T] {
    var result = [T]()
    for i in source {
        if predicate(i) {
            result.append(i)
        }
    }
    return result
}

let evens = goodFilter(Array(1...10)) { $0 % 2 == 0 }
print(evens) // [0, 2, 4, 6, 8, 10]
```

引数としてある型で宣言された配列と同じ型のインスタンスを受け取ってブール値を返す関数を受け取り、その返り値に同じ型の配列を返すというジェネリクス関数です。

中の処理は最初に書いたコードと同じです。`filter`と同じ結果が出力されていると思います。

また~~`Array`~~`SequenceType`の`extension`として宣言すれば通常の`filter`と同様にドット繋ぎで使用することができます。

# 配列の合計値を計算する

## 今までのやり方

次は少し複雑な処理として、先ほどフィルタリングした配列の合計値を計算してみましょう。

```swift
var evens = [Int]()
for number in 1...10 {
    if number % 2 == 0 {
        evens.append(number)
    }
}

var evenSum = 0
for number in evens {
    evenSum += number
}

print(evenSum) // 30
```

フィルタリングの処理は最初に使用したコードと同じです。合計値を出す処理もまた変数を用意して`for-in`でまわして足し合わせたものを変数に入れるといったものです。

## Functionalなやり方

```swift
let evenSum = Array(1...10).filter { $0 % 2 == 0 }
    .reduce(0) { (total, number) -> Int in
        return total + number
}

print(evenSum) // 30
```

まず`filter`で処理された`[0, 2, 4, 6, 8, 10]`が渡されています。`reduce`は初期値と配列の各要素に対して行われる関数で結合された値を返す高階関数です。

前回同様省略できる箇所を削ると以下のような書き方になります。

```swift
let evenSum = Array(1...10).filter { $0 % 2 == 0 }
    .reduce(0) { $0 + $1 }

print(evenSum) // 30
```

**追記**：`{ $0 + $1 }`は2つの引数を取る関数(クロージャ)ですが`+`自体が2引数で返り値のある関数なのでこういった書き方もできます。@ken0nekさんご教授ありがとうございました。

```swift
(0...10).filter { $0 % 2 == 0 }.reduce(0, combine: +)
```

**追記**：また今回は**配列(`Array`)**を指定していますが、実際`filter`や`reduce`は`SequenceType`のprotocolで定義されているので上記の`(1...10).filter`のように**`Range`**で直接呼び出すことができます。@yuta-tさんご教授ありがとうございました。

今回は少し複雑なので`reduce`のシグネチャを見てみましょう。

```swift
func reduce<U>(initial: U, combine: (U, T) -> U) -> U
```

最初のパラメータ`initial`は今回合計値を計算するので`Int`型の`0`が入りました。次の`combine`で結合する処理を行っていることが分かります。

`combine`では二つの引数を取り、一つ目の引数は前に`combine`で返された値(最初は初期値)が渡されます。二つ目の引数には配列の各要素が渡されます。そして`reduce`の返り値には`combine`で最後に処理された値が返されます。

文章で書くと分かりづらいですよね。そう言えば頭の良い人が「`reduce`はパックマンがエサを喰っているのをイメージするといい」って言ってました。

`[1, 8, 2, 5]`の配列を上記の合計値を計算させる`reduce`にかける時のイメージです。最初に`initial`というエサを食べたパックマンが動き出します…

![packman-1.png](https://qiita-image-store.s3.amazonaws.com/0/83361/a5589bd8-ffa5-83bd-254e-07221e7e3a1d.png)

このパックマン達は食べると単純に食べたエサ分太る(足す)という性質を持っています。

![packman-2.png](https://qiita-image-store.s3.amazonaws.com/0/83361/933bea25-16a5-c766-68bc-e9f1bab59d16.png)

太ったパックマンはそのまま次のエサを食べてまた太ります…

![packman-3.png](https://qiita-image-store.s3.amazonaws.com/0/83361/4f435e9b-3e6b-1615-93e9-4f92faef33f0.png)

これを最後のエサまで続けます…

![packman-4.png](https://qiita-image-store.s3.amazonaws.com/0/83361/b138bacc-224c-a119-5c3c-a76fcacd86c7.png)

そして体内に蓄えた**返り値**を返してきます…

![packman-5.png](https://qiita-image-store.s3.amazonaws.com/0/83361/832555e7-1656-c85e-8933-1b9d8e5ac004.png)

厳密に言うとパックマンは毎回自身の**返り値**を食べてからエサを食べるというのが正しいと思うのですが、絵にしたくないのでご了承ください…

## その他の使用方法

`reduce`は配列の要素を全てなめて何かしらの結果を返す処理をするにはとても強力な関数です。以下に例を示します。

```swift
let maxNumber = [1, 8, 2, 5].reduce(0) { max($0, $1) }
print(maxNumber) // 8
```

これは配列の要素の中で一番大きな値を取り出す処理です。前の要素(最初は初期値)と後の要素を`max`関数で比べて最後に返された値が`maxNumber`に代入されます。

```swift
let numbers = [1, 8, 2, 5].reduce("numbers: ") { $0 + "\($1) "}
print(numbers) // numbers: 1 8 2 5
```

`Int`型の配列の要素を`String`型の文字列連結して返すこともできます。初期値には最初に表示したい文字列を入れています。

## リデュースを自作する

では`filter`と同様に`reduce`を自作してみましょう。今回は~~`Array`~~`SequenceType`の`extension`を使っているのでドットで呼び出せます。

```swift
extension SequenceType {
    func goodReduce<T, U>(initial:U, combiner:(U, T) -> U) -> U {
        var current = initial
        for item in self {
            if let item = item as? T {
                current = combiner(current, item)
            }
        }
        return current
    }
}

let maxNumber = [1, 8, 2, 5].goodReduce(0) { current, number in max(current, number) }
print(maxNumber) // 8
```

まず初期値の`initial`の型`U`と配列の各要素の型`T`を宣言しています。中の処理としては前述した通り、各要素の`item`がある限り`current`に`combiner`関数の返り値を入れていくという単純な処理です。

```swift
extension SequenceType {
    func goodReduce<U>(initial:U, combiner:(U, Element) -> U) -> U {
        var current = initial
        for item in self {
            current = combiner(current, item)
        }
        return current
    }
}

let maxNumber = [1, 8, 2, 5].goodReduce(0) { max($0, $1) }
print(maxNumber) // 8
```

余談ですが先ほどの`T`で宣言していた型を`GeneratorType`プロトコルに準拠した`Element`を使用することで引数に`$0, $1, ...`の連番を与えられ、型のチェックも必要なくなります。

※`GeneratorType`について勉強中で、何故そうなるのか詳しく分かっていません。ご教授お願いいたします…

# おしまい

途中話が逸れているような気がしますがが、何となくSwiftの*Functional Programming*っぽい書き方に慣れることができました。

## 参考サイト

[CollectionType Protocol Reference](https://developer.apple.com/library/ios/documentation/Swift/Reference/Swift_CollectionType_Protocol/)
[SequenceType Protocol Reference](https://developer.apple.com/library/ios/documentation/Swift/Reference/Swift_SequenceType_Protocol/)
[Swift Functional Programming Tutorial](http://www.raywenderlich.com/82599/swift-functional-programming-tutorial)