Swiftエンジニアの高階関数実践

# はじめに

純粋関数型プログラミング言語である`Haskell`を参考に、以下の3つの構成で高階関数についてまとめていきます。

- <a href="http://qiita.com/shoheiyokoyama/items/04416501389c69544c5a">カリー化関数</a>
- 高階関数の実践
- ラムダ式

今回は、標準ライブラリで扱うことができる代表的な高階関数をいくつかまとめています。

# 高階関数

まずは、関数を引数で受け取る簡単な例を示します。以下の`applyTwice`は、受け取った関数を2回適用する関数です

```hs
applyTwice :: (a -> a) -> a -> a
applyTwice f x = f (f x)
```

関数を引数にする場合はかっこで囲む必要があります。上の例では一つの引数を取り、同じ型の値を返す関数を引数として受け取っています。
引数である関数を`x`に適用し、再び`f`を適用しています。動作例を以下に示します。

```bash
Prelude> applyTwice (+3) 10
16
Prelude> applyTwice (3:) [2]
[3, 3, 2]
```

セクション<sup>1</sup>を使った部分適用を使っています。とても単純な例ですが、汎用性が高い関数ができてるのがわかるかと思います。



<sup>1　中間関数に関しても部分適用することができ、これを中間関数をセクションするといいます。中間関数をセクションするには`(+3)`のように片側だけに値を置いて括弧で囲みます。</sup>

## `map`

`map`関数はリストに対して、引数の関数をすべての要素に適用し、新しい関数を返す関数です。実例を見るとわかりやすいので、定義を以下に示します。

```hs
map :: (a -> b) -> [a] -> [b]
map _ [] = []
map f (x:xs) = f x : map f xs
```

第一引数は、a型の値を受け取りb型の値を返す関数となっています。そのため、第二引数のリストはa型の要素の必要があります。二行目のパターンマッチは、リストが空だった場合は空のリストを返すという意味です。`_`はこの値を使用しない時に使う予約語で、使い捨ての変数を表しています。
`(x:xs)`はリストの最初の要素とその他の要素に分けるという意味で、最初の要素に関数を適用しその他の要素に対して再帰的に`map`を適用しています。


```bash
Prelude> map (+2) [1, 2, 3, 4]
[3, 4, 5, 6]
Prelude>　map (replicate 3) [1..3]
[[1,1,1],[2,2,2][3,3,3]]
```

このように、すべての要素に関数が適用されています。

## `zipWith`

`zipWith`は、二つのリストの各要素に関数を適用し1つのリストに結合する関数です。
こちらも実例を見るとわかりやすいので定義を以下に示します。

```hs
zipWith' :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith' _ [] _ = []
zipWith' _ _ [] = []
zipWith' f (x:xs) (y:ys) = f x y : zipWith' f xs ys
```

第一引数の関数はa型とb型の値からc型の値を返す関数となっています。そのため、第2引数のリストはa型の要素、第3引数のリストはb型の要素となっています。`zipWith'`<sup>2</sup>の使用例は以下のようになります。

```bash
Prelude> zipWith' (+3) 10
16
Prelude> zipWith' (3:) [2]
[3, 3, 2]
```

<sup>2 関数名の最後についてるアポストロフィ(')は、特別な意味を持たない関数名の一部として有効な文字です。慣習的に正格版の関数を表したり、少し変更したバージョンの関数に似た名前をつけるために利用されます。今回は標準ライブラリの`zipWith`関数を自作で定義しているために使用しています。</sup>


# `Swift`で高階プログラミング

`Haskell`でいくつか高階関数の例を示しましたが、今度は`Swift`で高階関数を扱っていきたいと思います。
高階関数の良いところの一つとして、汎用性のある関数が定義できるところです。
まず高階関数をつかっていない例として、各要素を二倍にして返す関数を定義してみます。

```swift
func double(_ array: [Int]) -> [Int] { 
    var result: [Int] = [] 
    for x in array { 
        result.append( x * 2) 
    } 
    return result 
}

double([3, 4]) // [6, 8]
```

この関数はあまり良いものとは言えません。`Int`を3倍にしたい時や、`Float`を扱いたい時などに変更が必要なためです。

これは高階関数とジェネリクスを使用することで解決できます。
標準ライブラリの`map`関数を自作で定義してみます。

```swift
func map<Element, T>(_ array: [Element], transform: (Element) -> T) -> [T] {
    var result: [T] = []
    for x in array {
        result.append(transform(x))
    }
    return result
}

map([2, 3]) { $0 * 2 } // [4, 6]
map([8, 4]) { $0 / 2 } // [4, 2]
map(["Swit", "swif"]) { $0 + "t" } // ["Swift", "swift"]
```

標準ライブラリの`map`と同じような挙動になっていますね。このように、高階関数を扱うことで汎用性がある関数を定義できます。

同様に`filter`も高階関数をつかってこのような定義で実現できます。

```swift
func filter<Element>(_ array: [Element], includeElement: (Element) -> Bool) -> [Element] {
    var result: [Element] = []
    for x in array where includeElement(x) {
        result.append( x)
    }
    return result
}

filter([3, 4, 5]) { $0 > 3 } //[4, 5]
```

### カリー関数

今度は少し難易度を上げて、引数と返り値に関数を扱うカリー関数を定義してみます。
ジェネリクスを用いて以下のように定義します。

```swift
func curry<A, B, C>(_ f: @escaping (A, B) -> C) -> (A) -> (B) -> C {
    return { x in
        { y in f(x, y) }
    }
}
```

ぱっと見、何ができるかわからないような関数ですね。
このカリー関数を使用して、要素をカウント分繰り返した配列を返してみます。

```swift
let repeateString = curry { (count: Int, element: String) -> [String] in
    Array(repeating: element, count: count)
}

let threeArray = repeateString(3)

threeArray("Swift") // ["Swift", "Swift", "Swift"]
threeArray("Haskell") // ["Haskell", "Haskell", "Haskell"]
```

`Swift`でも関数の部分適用ができていますね。部分適用された関数を使い回すことができます。

# 参考文献

- <a href="https://www.amazon.co.jp/Functional-Swift-Updated-3/dp/3000480056" target="_blank">Functional Swift: Updated for Swift 3</a>
- <a href="https://www.amazon.co.jp/%E3%81%99%E3%81%94%E3%81%84Haskell%E3%81%9F%E3%81%AE%E3%81%97%E3%81%8F%E5%AD%A6%E3%81%BC%E3%81%86-Miran-Lipova%C4%8Da/dp/4274068854" target="_blank">すごいHaskellたのしく学ぼう!</a>