Scalaプログラミングスタイル集をSwiftで

この記事は[Scalaプログラミングスタイル集](http://tech.recruit-mp.co.jp/server-side/post-6014/)をSwift2.0化するものです。詳しくはそちらをご覧ください。

***

# 手続きプログラミング

```swift
func fac(n: Int) -> Int {
    var result = 1
    for i in 1...n {
        result *= i
    }
    return result
}
```

# 普通の再帰

```swift
func fac(n: Int) -> Int {
    if n == 0 {
        return 1
    } else {
        return n * fac(n - 1)
    }
}
```

# パターンマッチ

```swift
func fac(n: Int) -> Int {
    switch n {
    case 0:
        return 1
    default:    //case _:でも通る
        return n * fac(n - 1)
    }
}
```

Swiftのパターンマッチイコールただの(割と自由に書ける)switch文という認識が抜けない。これじゃあ普通の再帰と一緒なのだが。

# 末尾再帰

```swift
func facAcc(acc: Int, n: Int) -> Int {
    if n == 0 {
        return acc
    } else {
        return facAcc(n * acc, n: n - 1)
    }
}
func fac(n: Int) -> Int {
    return facAcc(1, n: n)
}
```

facAccはローカル関数化できる、が、Swift1.2でやると__Local functions cannot reference themselves__とか言われる。

```swift
func fac(n: Int) -> Int {
    func facAcc(acc: Int, n: Int) -> Int {
        if n == 0 {
            return acc
        } else {
            return facAcc(n * acc, n: n - 1)
        }
    }
    return facAcc(1, n: n)
}
```

# 継続渡し

そもそもの合成関数をざっくり用意するところから始めないといけない。

```swift
infix operator ○ { }

func ○<T,U,V>(lhs: U -> V, rhs: T -> U) -> T -> V {
    return {x in lhs(rhs(x))}
}
```

↑を踏まえると

```swift
func facCps(k: Int -> Int, n: Int) -> Int {
    if n == 0 {
        return k(1)
    } else {
        return facCps(k ○ {n * $0}, n: n - 1)
    }
}
func fac(n: Int) -> Int {
    return facCps({$0}, n: n)
}
```

# Yコンビネータ

```swift
func Y<T, U>(x: T, f: (T, (T -> U)) -> U) -> U {
    return f(x){y in Y(y, f: f)}
}

func fac(n: Int) -> Int {
    return Y(n){ n, f in
        if n == 0 {
            return 1
        } else {
            return n * f(n - 1)
        }
    }
}
```

trailing closureを意識して本家とは仮引数の位置を代わってもらってみた。

# foldLeft
ScalaのfoldLeftはSwiftのreduceだしScalaのreduceは……あれ?

```swift
func fac(n: Int) -> Int {
    return (1...n).reduce(1, combine: *)
    //return (1...n).reduce(1){$0 * $1}
}
```

自力でfoldLeft(Swiftでいうところのreduce)を実装すると次のような感じ。reduceと同様SequenceTypeに対して実装してみる。

```swift
extension SequenceType {
    func foldLeft<U>(initial: U, combine: (U, Self.Generator.Element) -> U) -> U {
        var result = initial
        for element in self {
            result = combine(result, element)
        }
        return result
    }
}

func fac(n: Int) -> Int {
    return (1...n).foldLeft(1, combine: *)
}
```

# foldRight

ダメなfoldRightの場合

```swift
extension SequenceType {
    func foldRight<U>(initial: U, combine: (Self.Generator.Element, U) -> U) -> U {
        var result = initial
        let array = self.reverse()
        for element in array {
            result = combine(element, result)
        }
        return result
    }
}
func fac(n: Int) -> Int {
    return (1...n).foldRight(1, combine: *)
}
```

無限Stream対応版は種々のエラーに阻まれてなかなか大変なので省略。

# ポイントフリー

```swift
func fac(x: Int) -> Int {
    return ({(array: [Int]) in array.reduce(1, combine: *)} ○ {(x: Int) in Array(1...x)})(x)
}
```

# unfold

```swift
func unfold<T, U>(p: T -> Bool, h: T -> U, t: T -> T, a: T) -> Array<U> {
    if p(a) {
        return [U]()
    } else {
        return [h(a)] + unfold(p, h: h, t: t, a: t(a))
    }
}

func fac(n: Int) -> Int {
    return ({(array: [Int])in array.foldRight(1, combine: *)} ○ {(n: Int) in unfold({$0 == 0}, h: {x in x}, t: {$0 - 1}, a: n)})(n)
}
```

# Hylomorphism

```swift
func hylo<T,U,V>(v: V, f: (U, V) -> V, g: T -> (U, T), p: T -> Bool, t: T) -> V {
    if p(t) {
        return v
    } else {
        let (u, t_) = g(t)
        return f(u, hylo(v, f: f, g: g, p: p, t: t_))
    }
}

func fac(n: Int) -> Int {
    return hylo(1, f: *, g: {n in (n, n - 1)}, p: {$0 == 0}, t: n)
}
```

# Paramorphism

```Int版
func paraInt<T>(a: T, n: Int, f: (Int, T) -> T) -> T {
    if (n == 0) {
        return a
    } else {
        return f(n, paraInt(a, n: n - 1, f: f))
    }
}

func fac(n: Int) -> Int {
    return paraInt(1, n: n){n, m in n * m}
}
```

余談としてParamorphismの代表例、tailsが載っている。

```swift
func paraList<T, U>(b: U, array: [T], f: (T, [T], U) -> U) -> U {
    if array.isEmpty {
        return b
    } else {
        return f(array.first!, array, paraList(b, array: Array(array[1..<array.count]), f: f))
    }
}

func tails<T>(array: [T]) -> [[T]] {
    return paraList([[T]](), array: array){x, xs, tls in
        return [xs] + tls
    }
}
```

ただしこの実装だと出力がたとえば

```swift
[[1, 2], [2]]
```

となる。Scalaだと```List(List(1, 2), List(2), List())```。リスト構造じゃないのでしょうがない…?あと、部分配列の取り出しが気持ち悪い。[Swiftz](https://github.com/typelift/swiftz)とか使うと綺麗になるのかもしれない。

# 始代数、終余代数
量が多すぎ。Scalaに譲る

***

~~ここまで理解できていれば、Swiftを実務で使うのに十分な実力があると思います。(?)~~