LoginSignup
1
1

More than 5 years have passed since last update.

Swift で Scala の Option#fold を実装してみる

Last updated at Posted at 2019-04-16

あらすじ

関数型プログラミング勉強していたら、foldr と foldl の理解に躓きそうになっている僕。Swiftには foldl に該当する reduceがあるけど、foldr がよくわからずに理解しようと思っていたら、Scala の Option#foldに出会う。

Scala の Option#fold とは

def fold[B](ifEmpty:  B)(f: (A)  B): B

型を変換しながら、もとの値が Some か None かによって、別々の値を返す事が出来ます。

これをSwiftで実装したいわけです。Optional を extension で拡張してみましょう。


extension Optional {
    func fold<T>(_ ifEmpty: T, _ safe: (_ me: Wrapped) -> T ) -> T {
        if let wrapped = self {
            return safe(wrapped)
        } else {
            return ifEmpty
        }
    }
}

Optionalの値が nil だったら デフォルトとして 第一引数の<T> 型の値を、そうじゃなければ クロージャを実行した<T>型の戻り値を返すという関数になります。

オプショナルを if let で条件分岐するのはSwiftだと良く書くコードですが、これだとスッキリしますね!

//ベタな条件分岐を利用した処理
var some: Int?
var message: String
if let value = some {
    message = "\(value) is value"
} else {
    message = "value is nil"
}

//Optional fold を利用すると
let foldMessage = some.fold("value is nil"){ return "\($0) is value" }

使い方はこんな感じ。


struct Food {
    let calorie: UInt
    init(_ calorie: UInt) {
        self.calorie = calorie
    }
}

func eat(food: Food?) {
    let message = food.fold("ダイエット中だ!"){ return "\($0.calorie) kcal 肥えました!" }
    NSLog(message)
}

eat(food: Food(1000)) // 1000 kcal 肥えました!
eat(food: nil) // ダイエット中だ!
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1