Swiftで関数の合成

f(x)とg(x)という関数を合成して合成関数を作ることを式で表すと
(g ∘ f)(x) = g(f(x))
となります。関数gと関数fを合成したg ∘ fに引数xを渡した結果は、f(x)の結果を関数gに渡した結果と等しいということです。
（ここまで受け売り）

`∘`という記号は合成の記号です。
[写像の合成 - Wikipedia](https://ja.wikipedia.org/wiki/%E5%86%99%E5%83%8F%E3%81%AE%E5%90%88%E6%88%90)

現在提供されているSwiftでは関数合成を行う演算子は提供されていません。しかしGitHubのSwiftリポジトリにはinternalでExperimentalとして関数合成を行う`∘`演算子が定義されています。
https://github.com/apple/swift/blob/master/stdlib/internal/SwiftExperimental/SwiftExperimental.swift#L44

```swift
infix operator ∘ : CompositionPrecedence

precedencegroup CompositionPrecedence {
    associativity: left
    higherThan: TernaryPrecedence
}

public func ∘<T, U, V>(g: @escaping (U) -> V, f: @escaping (T) -> U) -> ((T) -> V) {
    return { g(f($0)) }
}
```

∘はU+2218 RING OPERATORだそうです。簡単に入力する方法がわかりませんが、試してみましょう。

```swift
func addOne(x: Int) -> Int {
    return x + 1
}

func addTwo(x: Int) -> Int {
    return x + 2
}

let addThree = addTwo ∘ addOne			// (Int) -> Int

let result1 = addTwo(x: addOne(x: 0))	// 3
let result2 = addThree(0)				// 3
```

1を加算する関数addOneと2を加算する関数addTwoを`addTwo ∘ addOne`として合成してaddThreeという関数を作り、addThreeに0を渡すと結果が3になりました。これは`addTwo(x: addOne(x: 0))`の結果と等しいので関数合成ができているようです。

次に4を掛けるmultiplyFourという関数を定義してaddThreeと組み合わせて新しい関数を作ってみます。

```swift
func multiplyFour(x: Int) -> Int {
    return x * 4
}

let op_add_multiply = multiplyFour ∘ addThree
let op_multiply_add = addThree ∘ multiplyFour

let result_add_multiply = op_add_multiply(0)	// 12
let result_multiply_add = op_multiply_add(0)	// 3
```

op_add_multiplyは`(x + 3) * 4`で、op_multiply_addは`(x * 4) + 3`となっているので結果が違っています。`∘`の右項から実行されているのが分かると思います。

さてここまでは引数と返値が同じ型でしたが違う型を使ってみましょう。

```swift
func toString(x: Int) -> String {
    return String(x)
}

let addAndToString = toString ∘ addThree		// (Int) -> String
let result_addAndToString = addAndToString(0)	// "3"
```

`(Int) -> Int`であるaddThree関数と`(Int) -> String`であるtoString関数を合成すると`(Int) -> String`型の関数ができました。この合成関数に0を与えると文字列"3"が得られます。3を加えて文字列に変換しているからです。fの返値とgの引数が同じ型であれば合成できるのです。`addThree ∘ toString`と記述してしまうとtoStringの返値とaddThreeの引数の型が違っているのでエラーになります。

では二つ以上の引数の関数と一つの引数の関数を合成してみるとどうなるでしょう。

```swift
func add(x: Int, y: Int) -> Int {
    return x + y
}

let addAndMultiplyFour = multiplyFour ∘ add					// ((Int, Int)) -> Int
let result_addAndMultiplyFour = addAndMultiplyFour((1, 2))	// 12
```

`(Int, Int) -> Int`と`(Int) -> Int`を合成してみると`((Int, Int)) -> Int`という関数になりました。引数がタプルになっています。

引数と返値がタプルの場合でも合成できるでしょうか。やってみましょう。

```swift
func addOneWithTuple(tuple: (Int, Int)) -> (Int, Int) {
    return (tuple.0 + 1, tuple.1 + 1)
}

func multiplyTwoWithTuple(tuple: (Int, Int)) -> (Int, Int) {
    return (tuple.0 * 2, tuple.1 * 2)
}

let addOneAndMultiplyTwoWithTuple = multiplyTwoWithTuple ∘ addOneWithTuple	// ((Int, Int)) -> (Int, Int)
let result_addOneAndMultiplyTwoWithTuple = addOneAndMultiplyTwoWithTuple((1, 2))	// (.0 4, .1 6)
```

((Int, Int)) -> (Int, Int)の関数が出来上がりました。

このように関数の合成を行うと二つの関数から新しい関数を作成することができます。関数型プログラミングでは単純で小さい関数を作成し、それらを合成してさまざまな機能を作成していくようです。Swiftで関数型プログラミングを行うには関数合成があると便利です。

ただし`∘`はExperimentalとして実装されているに過ぎません。iOSアプリなどでは自分で定義して利用するか、もしくは[Swiftz](https://github.com/typelift/Swiftz/)（もしくは簡易版の[Swiftx](https://github.com/typelift/Swiftx)）などのライブラリで提供されている関数合成演算子を利用するといいでしょう。ちなみにSwiftzでは`∘`ではなく`•`という文字が関数合成演算子として用いられています。この`•`はOption+8で入力することができ、より入力しやすいようになっています。