関数を定義する & 呼ぶ
func increment(n: Int) -> Int {
return n + 1
}
let increment = { (n: Int) in n + 1 }
let increment = { (n) in n + 1 }
let increment = { n in n + 1 }
let increment = { $0 + 1 }
increment(4) // 5
関数を返す関数
「カリー化」された関数を定義する構文があるのだが、廃止予定
func makeConst(n: Int)(_: Int) -> Int {
return n
}
makeConst(4)(7) // 4
今後は以下のようになる
func makeConst(n: Int) -> Int -> Int {
return { (_: Int) in n }
}
オプショナル
let m: Int? = nil
let n: Int? = 0
if let m = m, n = n {
print(m + n)
}
二重のオプショナル
let p: Int?? = nil // 外側が nil
let q: Int?? = nil as Int? // 内側が nil
let r: Int?? = 0
ちなみに Haskell だと
p = Nothing
q = Just (Nothing)
r = Just (Just 0)
Map
let a: Int? = nil
let b: Int? = 2
a.map { n in n + 1 } // nil
b.map { n in n + 1 } // 3
let a = [0, 1, 2, 3, 4]
a.map { n in n * 2 + 1 } // [1, 3, 5, 7, 9]
let s = Set([1, 2, 3])
s.map { x in x + 1 } // [3, 4, 2]
集合も map
すると配列になってしまう...
flatten
二重のリストを一重にする
[[1, 2], [3, 4]].flatten()
// [1, 2, 3, 4]
二重オプショナルの flatten
はない
flatMap
map
して flatten
する
[10, 20, 30].flatMap { n in [n, n + 1] }
// [10, 11, 20, 21, 30, 31]
func divide10(n: Int) -> Int? {
guard n != 0 else {
return nil
}
return 10 / n
}
(nil as Int?).flatMap(divide10) // nil
(0 as Int?).flatMap(divide10) // nil
(5 as Int?).flatMap(divide10) // 2
モノイドをプロトコルとして定義する
protocol Monoid {
init()
func + (left: Self, right: Self) -> Self
}
extension Int: Monoid {
}
extension Array: Monoid {
}
func reduce<S: SequenceType
where S.Generator.Element: Monoid>
(sequence: S) -> S.Generator.Element {
return sequence.reduce(
S.Generator.Element(), combine: +)
}
reduce([] as [Int]) // 0
reduce([] as [[Int]]) // []
reduce([0, 1, 2, 3]) // 6
reduce([[0, 1, 2], [3, 4], [5, 6, 7, 8]])
// [0, 1, 2, 3, 4, 5, 6, 7, 8]
Swift でできないこと
- 末尾呼び出し最適化
- 最適化器が頑張ればできることもある
- ファンクターやモナドをプロトコルとして定義する
- リストやオプショナルの
map
やflatMap
はシグネチャーが「同じ」だけで、プロトコルとしては共通化されていない
- リストやオプショナルの