Swift
関数型プログラミング

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


あらすじ

関数型プログラミング勉強していたら、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) // ダイエット中だ!