SlideShare a Scribd company logo
1 of 97
Download to read offline
My Sweet Swift
Agenda 
• Generics 
• Enumeration 
• Optional 
• Appendix
Agenda 
• Generics 
• Enumeration 
• Optional 
• Appendix 
}準備 
本題
Generics
Generics 
• 型をパラメータにとる関数・データ構造 
• 型情報を保ったまま、複数の型に同時に対応 
できる 
• とは?
例: 入力をそのまま返す関数 
func identity(input: Int) -> Int { 
return input 
} 
! 
let number = identity(42) // Int 
let string = identity("Lorem ipusm") // error
例: 入力をそのまま返す関数 
func identity(input: Any) -> Any { 
return input 
} 
! 
let number = identity(42) // Any 
let string = identity("Lorem ipsum") // Any 
! 
number * 2 // error 
string + string // error
例: 入力をそのまま返す関数 
func identity<T>(input: T) -> T { 
return input 
} 
! 
let number = identity(42) // Int 
let string = identity("Lorem ipsum") // String 
! 
number * 2 
string + string
例: map 
x 
f 
"(x)" 
func f(x: Int) -> String { 
return "(x)" 
}
例: map 
x [1, 2, 3] 
f 
"(x)"
例: map 
x [1, 2, 3] 
f 
"(x)" ["1", "2", "3"]
例: map 
x [1, 2, 3] 
f 
"(x)" ["1", "2", "3"] 
map([Int], Int -> String) -> [String]
例: map 
func f(x: Int) -> String { 
return "(x)" 
} 
! 
func map(xs: [Int], f: Int -> String) -> [String] { 
var ys = [String]() 
for x in xs { 
ys.append(f(x)) 
} 
return ys 
} 
! 
map([1, 2, 3], f) // ["1", "2", “3"] 
map([1, 2, 3], { "($0)" }) // ["1", "2", "3"]
例: map 
Int [Int] 
f 
String [String] 
map([Int], Int -> String) -> [String]
例: map 
T [T] 
T -> U 
U [U] 
map([T], T -> U) -> [U]
例: map 
func map<T, U>(xs: [T], f: T -> U) -> [U] { 
var ys = [U]() 
for x in xs { 
ys.append(f(x)) 
} 
return ys 
} 
! 
// [Int] -> [String] 
map([1, 2, 3], { "($0)" }) // ["1", "2", "3"] 
// [Int] -> [Double] 
map([1, 2, 3], { $0 * 2.0 }) // [2.0, 4.0, 6.0] 
// [Double] -> [CGRect] 
map([1, 2, 3], { CGRect(x: $0, y: $0, width: 100.0, height: 100.0) })
クラスの例: Stack 
class Stack<T> { 
private var array = [T]() 
func push(item: T) { 
array.append(item) 
} 
func pop() -> T { 
return array.removeLast() 
} 
} 
! 
let stack = Stack<Int>() 
stack.push(1) 
stack.push(2) 
stack.push(3) 
stack.pop() // 3 
stack.pop() // 2 
stack.pop() // 1
Enumerations
Enums 
enum BloodType { 
case A, B, O, AB 
} 
! 
struct Person { 
var bloodType: BloodType 
} 
! 
var p = Person(bloodType: BloodType.A) 
var q = Person(bloodType: .A) 
q.bloodType = .AB
Enums 
• ObjCのEnumと違って、「値」を持たない 
• ex. 東西南北に整数を割り当てる意味? 
• 従来通りに値を持たせることもできる 
• 文字列もOK
…with associated values 
/// ダイアログのUI要素を指定するenum。 
enum DialogItem { 
case TextButton(title: String, identifier: String) 
case GrayButton(title: String, identifier: String) 
case Text(String) 
case Title(String) 
case Margin(CGFloat) 
case Group([DialogItem]) 
} 
! 
let item1 = DialogItem.Margin(20) 
let item2 = DialogItem.Text("String")
Associated Values 
• enumの各状態に値を紐づけることができる 
• 型が違っていてもいい 
• 単なる列挙というよりは、「複数の型のどれ 
か」を表す型になる
Switchで値を展開 
switch item { 
case let .Title(title): 
println("Title: (title)") 
case let .Text(text): 
println("Text: (text)") 
case let .TextButton(title: title, identifier: identifier): 
/// 
case let .GrayButton(title: title, identifier: identifier): 
/// 
case let .Group(subitems): 
/// 
default: break 
}
例: DialogViewController 
let items: [DialogViewController.DialogItem] = [ 
.Title("ダイアログ"), 
.Text("表示要素を配列で渡すだけで、自在にダイアログを作ることができます。"), 
.TextButton(title: "ボタン", identifier: "button1"), 
.Margin(60), 
.Group([ 
.Group([.Text("二段組み"), .Text("にも")]), 
.Group([.Text("対応"), .Text("(たぶん)")]) 
]), 
.Group([ 
.TextButton(title: "ボタン", identifier: "button2"), 
.GrayButton(title: "ボタン", identifier: "button3"), 
.TextButton(title: "ボタン", identifier: "button4") 
]) 
] 
let dialog = DialogViewController(items: items, callback: nil) 
presentViewController(dialog, animated: true, completion: nil)
簡単な例: Failable 
• 「失敗するかもしれない」結果を記述する 
• 失敗すればFailed、成功すればSucceeded 
• 成功した場合は結果をAssociated Valueに持 
つ
例: Failable<T> 
enum Failable<T> { 
case Succeeded(T) // 成功したときの値 
case Failed // 失敗フラグ 
init(_ value: T) { 
self = .Succeeded(value) 
} 
}
例: Failable<T> 
// 2で割れたら割るけど割れなかったらあきらめる(やる気のない)関数 
func failableHalve(x: Int) -> Failable<Int> { 
if x % 2 == 0 { 
return .Succeeded(x / 2) 
} else { 
return .Failed 
} 
} 
! 
switch failableHalve(12) { 
case let .Succeeded(r): 
println("Answer: (r)") 
default: 
println("Odd Number") 
}
それって 
// 2で割れたら割るけど割れなかったらあきらめる(やる気のない)関数 
func failableHalve(x: Int) -> Optional<Int> { 
if x % 2 == 0 { 
return .Some(x / 2) 
} else { 
return .None 
} 
} 
! 
switch failableHalve(12) { 
case let .Some(r): 
println("Answer: (r)") 
default: 
println("Odd Number") 
}
Optionalなのでは? 
// 2で割れたら割るけど割れなかったらあきらめる(やる気のない)関数 
func failableHalve(x: Int) -> Int? { 
if x % 2 == 0 { 
return x / 2 
} else { 
return nil 
} 
} 
!! 
if let r = failableHalve(12) { 
println("Answer: (r)") 
} else { 
println("Odd Number") 
}
Optional
太古よりnullは人々を苦しめてきた
Optional以前 
• オブジェクトとはポインタである 
• 特別なアドレス(多くの場合0)をNULLと呼 
び、そこを指すポインタを「無効なオブジェ 
クト」として扱う
問題点 
• NULLを無効な値だと知っているのは実行中のプ 
ログラムとプログラマだけ 
• コンパイラには他のポインタ値と区別できない 
• →実行時に落ちる 
• 予期せぬNULLが紛れ込まないように「気をつけ 
る」「確認する」ことしかできなかった
Optionalのいいところ 
• 「無効な値」という概念を型にしたことで、 
意味論ではなく構文論として扱える 
• 無効な値を扱う操作が「書けない」文法
Optional<T> 
enum Optional<T> : Reflectable, NilLiteralConvertible { 
case None 
case Some(T) 
! 
/// Construct a `nil` instance. 
init() 
! 
/// Construct a non- `nil` instance that stores `some`. 
init(_ some: T) 
! 
/// If `self == nil`, returns `nil`. Otherwise, returns `f(self!)`. 
func map<U>(f: (T) -> U) -> U? 
! 
/// Returns a mirror that reflects `self`. 
func getMirror() -> MirrorType 
! 
/// Create an instance initialized with `nil`. 
init(nilLiteral: ()) 
}
Optional<T> 
• 実体はGeneric Enum 
• 実はちょっと嘘で、特別扱いを受けている 
• cf. http://qiita.com/koher/items/ 
5dd6ce7427e7ecff4249 
• (Failable<T>と同じように)箱です
Optional as 箱 
• 「Tかもしれない」ではなく、「Tの入る箱」 
• 値に触るためには箱を開ける必要がある 
• binding/coalescing/unwrapping 
• 箱を開けずに操作する方法もある 
• mapping/chaining
Optional Binding 
var optionalInt: Int? 
! 
if let int = optionalInt { // int: Int 
println("optionalInt was (int)") 
} else { 
println("optionalInt was nil") 
} 
! 
var array = [1, 2, 3, 4] 
while let item = array.last { // item: Int 
println("(item)") 
array.removeLast() 
}
箱を開ける: Optional Binding 
• 値があればtrueに評価されつつ中身を変数に 
束縛(bind)してくれる 
• 一度に一個しかbindできないのは多少不便
Optional Coalescing 
optionalInt ?? 3 
! 
// ↓と等価: 
optionalInt != nil ? optionalInt! : 3 
! 
// あるいは: 
func coalesce<T>(lhs: T?, rhs: @autoclosure () -> T) -> T { 
if let lhs = lhs { 
return lhs 
} else { 
return rhs() 
} 
} 
coalesce(optionalInt, 3)
箱を開ける: Optional Coalescing 
• 開けられたら開ける 
• 開けられなかったら開けない 
• かわりにデフォルト値を返す
無理矢理開ける: Forced Unwrapping 
optionalInt! 
• 値があればそれが返るが、なければ落ちる 
• 落ちる可能性があるので使うべきではない 
• 安全が保証できるなら構わないが……
箱から出さずに進める方法 
• Optional mapping 
• Optional chaining
Optional Mapping 
/// 3倍する関数 
func triple(x: Int) -> Int { 
return x * 3 
} 
! 
optionalInt = 2 
// 以下はすべて.Some 6 
optionalInt.map(triple) 
map(optionalInt, triple) 
optionalInt.map({ $0 * 3 })
箱を開けない: Optional Mapping 
• 箱の中から別の箱の中へ 
• 値があればそれを移して別の箱(Optional) 
を作る 
• nilならばnilを返す
Optional Mapping 
T 
U 
T -> U 
T? 
U? 
map(T?, T -> U) -> U?
Optional Chaining 
class A { 
var b: B? 
} 
! 
class B { 
var c: C? 
} 
! 
class C { 
var i: Int = 1 
} 
var a: A? = A() 
// a.b.c.iにアクセスしたい
Optional Chaining 
var a: A? 
! 
if let a = a { 
if let b = a.b { 
if let c = b.c { 
println("We finally find (c.i)!") 
} 
} 
}
Optional Chaining 
var a: A? 
! 
if let i = a?.b?.c?.i { 
println("Optional chaining makes (i)t easy.") 
}
箱を開けない: Optional Chaining 
• 失敗するかもしれない呼び出しを連鎖できる 
• 失敗すればその先には進まずnil
Optional Chaining 
a?.b?.c?.i 
A? 
aはA?型の変数
× 
Optional Chaining 
a.b 
A? 
A?型にbというメンバはない
Optional Chaining 
a?.b?.c?.i 
A? 
a?.bという形にする
Optional Chaining 
a?.b?.c?.i 
A() 
or 
nil 
aはnilかSomeのどちらか
Optional Chaining 
a?.b?.c?.i 
A() 
B? 
or 
nil 
Someならばbに触れる
Optional Chaining 
a?.b?.c?.i 
A() 
B? 
or 
nil nil 
nilならそれで終わり
Optional Chaining 
a?.b?.c?.i 
A() 
B? 
or 
nil nil 
bはB?型の変数
Optional Chaining 
a?.b?.c?.i 
A() 
B() 
C? 
or 
or 
nil nil 
nil 
同じように分岐
Optional Chaining 
a?.b?.c?.i 
A() 
B() 
C() 
7 
or 
or 
or 
nil nil 
nil 
nil 
以下同文
書き直してみる 
extension Optional { 
func chain<U>(f: T -> U?) -> U? { 
if let s = self { 
return f(s) 
} else { 
return nil 
} 
} 
} 
! 
if let i = a.chain({ $0.b }).chain({ $0.c }).chain({ $0.i }) { 
println("(i)") 
} 
! 
// (正確には↓だが説明は省略(結果は等しくなる)) 
// let k = a.chain({ $0.b.chain({ $0.c.chain({ $0.i }) }) })
なぜ書き直したの? 
• メンバ関数以外にも使えるようにしたい 
• これが今日の主役です
Failable Halve 
Int Int? 
// 2で割れたら割るけど割れなかったらあきらめる(やる気のない)関数 
func failableHalve(x: Int) -> Int? { 
if x % 2 == 0 { 
return x / 2 
} else { 
return nil 
} 
} 
! 
if let a = failableHalve(x) { 
println("Halve((x)) = (a)") 
} else { 
println("Failed") 
}
Failable Halve Again 
Int Int? 
if let a = failableHalve(x) { 
if let b = failableHalve(a) { 
println("Halve^2((x)) = (b)") 
} else { 
println("Failed") 
} 
} else { 
println("Failed") 
} 
Int Int?
Failable Halve The 3rd 
Int Int? 
if let a = failableHalve(x) { 
if let b = failableHalve(a) { 
if let c = failableHalve(b) { 
println("Halve^3((x)) = (c)") 
} else { 
println("Failed") 
} 
} else { 
println("Failed") 
} 
} else { 
println("Failed") 
} 
Int Int? Int Int?
Failable Halve Chaining 
Int Int? 
if let a = failableHalve(x).chain(failableHalve).chain(failableHalve) { 
println("Halve^3((x)) = (a)") 
} else { 
println("Failed") 
} 
Int? Int?
Failable Halve Chaining 
Int Int? 
Int? Int? 
24 
failableHalve(24) // Some 12 
failableHalve(24).chain(failableHalve) // Some 6 
failableHalve(24).chain(failableHalve).chain(failableHalve) // Some 3 
failableHalve(24).chain(failableHalve).chain(failableHalve).chain(failableHalve) // nil 
! 
36 
failableHalve(36) // Some 18 
failableHalve(36).chain(failableHalve) // Some 9 
failableHalve(36).chain(failableHalve).chain(failableHalve) // nil 
failableHalve(36).chain(failableHalve).chain(failableHalve).chain(failableHalve) // nil
Optional Chaining 
t: T 
T
Optional Chaining 
T f U? 
f(t): U?
Optional Chaining 
U g V? 
T f U? 
f(t): U?
Optional Chaining 
g 
f V? 
T U? 
f(t).chain(g): V?
Optional Chaining 
g 
V h W? 
f V? 
T U? 
f(t).chain(g): V?
Optional Chaining 
g h W? 
f V? 
T U? 
f(t).chain(g).chain(h): W?
Appendix
Array Mapping 
T [T] 
T -> U 
U [U] 
map([T], T -> U) -> [U]
Optional Mapping 
T 
U 
T -> U 
T? 
U? 
map( T?, T -> U) -> U?
Optional<T>とArray<T> 
• T型の値が入った箱 
• mapを使えば箱の中身だけを写すことができ 
る
Optional as 状況 
• ところで、Optionalは「nilかもしれない」と 
いう状況(context)を表現していた 
• Arrayはどんな状況を表現している? 
• →「値が確定していない」
Array as 状況 
Kyoto
目がさめると京都にいた 
(0, 0) 
Kyoto
歩く 
(0, 1) 
(-1,0) (1, 0) 
(0,-1) 
Kyoto
歩く 
/// 座標 
typealias Position = (Int, Int) 
! 
/// 東西南北のどこかへ歩きます 
func walk(from: Position) -> [Position] { 
let (x, y) = from 
return [(x - 1, y), (x + 1, y), (x, y - 1), (x, y + 1)] 
} 
! 
walk((0, 0)) // [(-1, 0), (1, 0), (0, -1), (0, 1)]
さらに歩く 
Kyoto
さらに歩く 
Kyoto
Array Chaining 
T [U] 
U 
[V] 
V [W]
Array Chaining 
extension Array { 
func chain<U>(f: Element -> [U]) -> [U] { 
var ys = [U]() 
for x in self { 
ys += f(x) 
} 
return ys 
} 
} 
! 
walk((0, 0)).chain(walk).chain(walk)
もっと状況を! 
• 「値が非同期で返ってくる」も状況
BFTask 
doHeavyJobAsync1().continueWithBlock { 
(task: BFTask!) -> BFTask in 
let result = task.result as NSString 
self.resultLabel1.text = result 
self.resultLabel2.text = "処理中..." 
return self.doHeavyJobAsync2(result) 
}.continueWithBlock { 
(task: BFTask!) -> BFTask in 
let result = task.result as NSString 
self.resultLabel2.text = result 
self.resultLabel3.text = "処理中..." 
return self.doHeavyJobAsync3(result) 
}.continueWithBlock { 
(task: BFTask!) -> AnyObject! in 
let result = task.result as NSString 
self.resultLabel3.text = result 
return nil 
}
BFTask 
private func doHeavyJobAsync2(prevResult: String) -> BFTask { 
var completionSource = BFTaskCompletionSource() 
// 5秒待ちの処理 
// 実用的には、AFNetworkingのcompletionブロック等でsetResultするイメージ 
Util.delay(5, { 
completionSource.setResult(prevResult + "オワタ") 
}) 
return completionSource.task 
}
Task<T> 
class Task<T: AnyObject> { 
private let task: BFTask 
! 
init(task: BFTask) { 
self.task = task 
} 
var result: T? { 
return task.result as? T 
} 
func chain<U: AnyObject>(f: (T -> Task<U>)) -> Task<U> { 
let newTask = task.continueWithBlock { f($0.result as T).task } 
return Task<U>(task: newTask) 
} 
}
Taskを返す関数 
private func doHeavyJobAsync2(prevResult: NSString) -> Task<NSString> { 
let source = Source<NSString>() 
// 5秒待ちの処理 
// 実用的には、AFNetworkingのcompletionブロック等でsetResultするイメージ 
delay(5, { 
source.setResult(prevResult + "オワタ" as NSString) 
}) 
return source.task 
}
Task Chaining 
T U 
U 
V 
V W 
非同期 
非同期 
非同期
Task Chaining 
func heavyTask1(Void) -> Task<NSString> { 
return delayedTask(5) { 
NSLog("First Task (no params)") 
return "123" as NSString 
} 
} 
! 
func heavyTask2(string: NSString) -> Task<NSNumber> { 
return delayedTask(5) { 
NSLog("Second Task (param: (string))") 
return NSNumber(integer: (string as String).toInt() ?? 0) 
} 
} 
! 
func heavyTask3(number: NSNumber) -> Task<NSNumber> { 
return delayedTask(5) { 
NSLog("Third Task (param: (number))") 
return NSNumber(integer: number.integerValue * 2) 
} 
}
Task Chaining 
NSLog("Start") 
heavyTask1().chain(heavyTask2).chain(heavyTask3) 
NSLog("End") 
2014-11-27 21:15:24.659 MySweetSwift[18362:314049] Start 
2014-11-27 21:15:24.663 MySweetSwift[18362:314049] End 
2014-11-27 21:15:29.663 MySweetSwift[18362:314049] First Task (no params) 
2014-11-27 21:15:35.136 MySweetSwift[18362:314049] Second Task (param: 123) 
2014-11-27 21:15:40.636 MySweetSwift[18362:314049] Third Task (param: 123)
まとめ 
• Optionalはかわいい! 
• ArrayとOptionalは似ている 
• すなわち、箱であり、状況である 
• 非同期処理も同じように見ることができる 
• Optional Chainingのような書きかたができて、そ 
れはBFTaskに似ている
参考文献
以上

More Related Content

What's hot

Ekmett勉強会発表資料
Ekmett勉強会発表資料Ekmett勉強会発表資料
Ekmett勉強会発表資料時響 逢坂
 
今から始める Lens/Prism
今から始める Lens/Prism今から始める Lens/Prism
今から始める Lens/PrismNaoki Aoyama
 
Van laarhoven lens
Van laarhoven lensVan laarhoven lens
Van laarhoven lensNaoki Aoyama
 
関数型プログラミング入門 with OCaml
関数型プログラミング入門 with OCaml関数型プログラミング入門 with OCaml
関数型プログラミング入門 with OCamlHaruka Oikawa
 
すごいHaskell楽しく学ぼう 第6章
すごいHaskell楽しく学ぼう 第6章すごいHaskell楽しく学ぼう 第6章
すごいHaskell楽しく学ぼう 第6章aomori ringo
 
Real World OCamlを読んでLispと協調してみた
Real World OCamlを読んでLispと協調してみたReal World OCamlを読んでLispと協調してみた
Real World OCamlを読んでLispと協調してみたblackenedgold
 
関数プログラミング入門
関数プログラミング入門関数プログラミング入門
関数プログラミング入門Hideyuki Tanaka
 
Scala の関数型プログラミングを支える技術
Scala の関数型プログラミングを支える技術Scala の関数型プログラミングを支える技術
Scala の関数型プログラミングを支える技術Naoki Aoyama
 
メタプログラミング C#
メタプログラミング C#メタプログラミング C#
メタプログラミング C#Fujio Kojima
 
F#入門 ~関数プログラミングとは何か~
F#入門 ~関数プログラミングとは何か~F#入門 ~関数プログラミングとは何か~
F#入門 ~関数プログラミングとは何か~Nobuhisa Koizumi
 
C# 式木 (Expression Tree) ~ LINQをより深く理解するために ~
C# 式木 (Expression Tree) ~ LINQをより深く理解するために ~C# 式木 (Expression Tree) ~ LINQをより深く理解するために ~
C# 式木 (Expression Tree) ~ LINQをより深く理解するために ~Fujio Kojima
 
これから Haskell を書くにあたって
これから Haskell を書くにあたってこれから Haskell を書くにあたって
これから Haskell を書くにあたってTsuyoshi Matsudate
 
たのしい高階関数
たのしい高階関数たのしい高階関数
たのしい高階関数Shinichi Kozake
 

What's hot (20)

Haskell Lecture 2
Haskell Lecture 2Haskell Lecture 2
Haskell Lecture 2
 
 
  
 
 
Ekmett勉強会発表資料
Ekmett勉強会発表資料Ekmett勉強会発表資料
Ekmett勉強会発表資料
 
今から始める Lens/Prism
今から始める Lens/Prism今から始める Lens/Prism
今から始める Lens/Prism
 
Van laarhoven lens
Van laarhoven lensVan laarhoven lens
Van laarhoven lens
 
関数型プログラミング入門 with OCaml
関数型プログラミング入門 with OCaml関数型プログラミング入門 with OCaml
関数型プログラミング入門 with OCaml
 
すごいHaskell楽しく学ぼう 第6章
すごいHaskell楽しく学ぼう 第6章すごいHaskell楽しく学ぼう 第6章
すごいHaskell楽しく学ぼう 第6章
 
Real World OCamlを読んでLispと協調してみた
Real World OCamlを読んでLispと協調してみたReal World OCamlを読んでLispと協調してみた
Real World OCamlを読んでLispと協調してみた
 
関数プログラミング入門
関数プログラミング入門関数プログラミング入門
関数プログラミング入門
 
Scala の関数型プログラミングを支える技術
Scala の関数型プログラミングを支える技術Scala の関数型プログラミングを支える技術
Scala の関数型プログラミングを支える技術
 
メタプログラミング C#
メタプログラミング C#メタプログラミング C#
メタプログラミング C#
 
F#入門 ~関数プログラミングとは何か~
F#入門 ~関数プログラミングとは何か~F#入門 ~関数プログラミングとは何か~
F#入門 ~関数プログラミングとは何か~
 
Swiftおさらい
SwiftおさらいSwiftおさらい
Swiftおさらい
 
C# 式木 (Expression Tree) ~ LINQをより深く理解するために ~
C# 式木 (Expression Tree) ~ LINQをより深く理解するために ~C# 式木 (Expression Tree) ~ LINQをより深く理解するために ~
C# 式木 (Expression Tree) ~ LINQをより深く理解するために ~
 
MP in Scala
MP in ScalaMP in Scala
MP in Scala
 
Scala with DDD
Scala with DDDScala with DDD
Scala with DDD
 
これから Haskell を書くにあたって
これから Haskell を書くにあたってこれから Haskell を書くにあたって
これから Haskell を書くにあたって
 
たのしい高階関数
たのしい高階関数たのしい高階関数
たのしい高階関数
 
Actor&stm
Actor&stmActor&stm
Actor&stm
 
MP in Haskell
MP in HaskellMP in Haskell
MP in Haskell
 

Similar to 20141128 iOSチーム勉強会 My Sweet Swift

Implicit Explicit Scala
Implicit Explicit ScalaImplicit Explicit Scala
Implicit Explicit ScalaKota Mizushima
 
競技プログラミングのためのC++入門
競技プログラミングのためのC++入門競技プログラミングのためのC++入門
競技プログラミングのためのC++入門natrium11321
 
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜How wonderful to be (statically) typed 〜型が付くってスバラシイ〜
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜Hiromi Ishii
 
TypeScript 1.0 オーバービュー
TypeScript 1.0 オーバービューTypeScript 1.0 オーバービュー
TypeScript 1.0 オーバービューAkira Inoue
 
Pythonで始めるDropboxAPI
Pythonで始めるDropboxAPIPythonで始めるDropboxAPI
Pythonで始めるDropboxAPIDaisuke Igarashi
 
Clojure programming-chapter-2
Clojure programming-chapter-2Clojure programming-chapter-2
Clojure programming-chapter-2Masao Kato
 
Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3Ransui Iso
 
C++0x in programming competition
C++0x in programming competitionC++0x in programming competition
C++0x in programming competitionyak1ex
 
Python standard 2022 Spring
Python standard 2022 SpringPython standard 2022 Spring
Python standard 2022 Springanyakichi
 
Scalaによる型安全なエラーハンドリング
Scalaによる型安全なエラーハンドリングScalaによる型安全なエラーハンドリング
Scalaによる型安全なエラーハンドリングTanUkkii
 
Boost jp9 program_options
Boost jp9 program_optionsBoost jp9 program_options
Boost jp9 program_optionsnyaocat
 
速くなければスマフォじゃない - インターンバージョン-
速くなければスマフォじゃない - インターンバージョン-速くなければスマフォじゃない - インターンバージョン-
速くなければスマフォじゃない - インターンバージョン-Kazunari Hara
 
モナドハンズオン前座
モナドハンズオン前座モナドハンズオン前座
モナドハンズオン前座bleis tift
 
命令プログラミングから関数プログラミングへ
命令プログラミングから関数プログラミングへ命令プログラミングから関数プログラミングへ
命令プログラミングから関数プログラミングへNaoki Kitora
 
ノンプログラマーでも明日から使えるJavaScript簡単プログラム 先生:柳井 政和
ノンプログラマーでも明日から使えるJavaScript簡単プログラム 先生:柳井 政和ノンプログラマーでも明日から使えるJavaScript簡単プログラム 先生:柳井 政和
ノンプログラマーでも明日から使えるJavaScript簡単プログラム 先生:柳井 政和schoowebcampus
 
LastaFluteでKotlinをはじめよう
LastaFluteでKotlinをはじめようLastaFluteでKotlinをはじめよう
LastaFluteでKotlinをはじめようShinsuke Sugaya
 

Similar to 20141128 iOSチーム勉強会 My Sweet Swift (20)

Implicit Explicit Scala
Implicit Explicit ScalaImplicit Explicit Scala
Implicit Explicit Scala
 
Map
MapMap
Map
 
競技プログラミングのためのC++入門
競技プログラミングのためのC++入門競技プログラミングのためのC++入門
競技プログラミングのためのC++入門
 
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜How wonderful to be (statically) typed 〜型が付くってスバラシイ〜
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜
 
TypeScript 1.0 オーバービュー
TypeScript 1.0 オーバービューTypeScript 1.0 オーバービュー
TypeScript 1.0 オーバービュー
 
Pythonで始めるDropboxAPI
Pythonで始めるDropboxAPIPythonで始めるDropboxAPI
Pythonで始めるDropboxAPI
 
たのしい関数型
たのしい関数型たのしい関数型
たのしい関数型
 
Clojure programming-chapter-2
Clojure programming-chapter-2Clojure programming-chapter-2
Clojure programming-chapter-2
 
boost tour 1.48.0 all
boost tour 1.48.0 allboost tour 1.48.0 all
boost tour 1.48.0 all
 
Pythonintro
PythonintroPythonintro
Pythonintro
 
Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3
 
C++0x in programming competition
C++0x in programming competitionC++0x in programming competition
C++0x in programming competition
 
Python standard 2022 Spring
Python standard 2022 SpringPython standard 2022 Spring
Python standard 2022 Spring
 
Scalaによる型安全なエラーハンドリング
Scalaによる型安全なエラーハンドリングScalaによる型安全なエラーハンドリング
Scalaによる型安全なエラーハンドリング
 
Boost jp9 program_options
Boost jp9 program_optionsBoost jp9 program_options
Boost jp9 program_options
 
速くなければスマフォじゃない - インターンバージョン-
速くなければスマフォじゃない - インターンバージョン-速くなければスマフォじゃない - インターンバージョン-
速くなければスマフォじゃない - インターンバージョン-
 
モナドハンズオン前座
モナドハンズオン前座モナドハンズオン前座
モナドハンズオン前座
 
命令プログラミングから関数プログラミングへ
命令プログラミングから関数プログラミングへ命令プログラミングから関数プログラミングへ
命令プログラミングから関数プログラミングへ
 
ノンプログラマーでも明日から使えるJavaScript簡単プログラム 先生:柳井 政和
ノンプログラマーでも明日から使えるJavaScript簡単プログラム 先生:柳井 政和ノンプログラマーでも明日から使えるJavaScript簡単プログラム 先生:柳井 政和
ノンプログラマーでも明日から使えるJavaScript簡単プログラム 先生:柳井 政和
 
LastaFluteでKotlinをはじめよう
LastaFluteでKotlinをはじめようLastaFluteでKotlinをはじめよう
LastaFluteでKotlinをはじめよう
 

20141128 iOSチーム勉強会 My Sweet Swift

  • 2. Agenda • Generics • Enumeration • Optional • Appendix
  • 3. Agenda • Generics • Enumeration • Optional • Appendix }準備 本題
  • 5. Generics • 型をパラメータにとる関数・データ構造 • 型情報を保ったまま、複数の型に同時に対応 できる • とは?
  • 6. 例: 入力をそのまま返す関数 func identity(input: Int) -> Int { return input } ! let number = identity(42) // Int let string = identity("Lorem ipusm") // error
  • 7. 例: 入力をそのまま返す関数 func identity(input: Any) -> Any { return input } ! let number = identity(42) // Any let string = identity("Lorem ipsum") // Any ! number * 2 // error string + string // error
  • 8. 例: 入力をそのまま返す関数 func identity<T>(input: T) -> T { return input } ! let number = identity(42) // Int let string = identity("Lorem ipsum") // String ! number * 2 string + string
  • 9. 例: map x f "(x)" func f(x: Int) -> String { return "(x)" }
  • 10. 例: map x [1, 2, 3] f "(x)"
  • 11. 例: map x [1, 2, 3] f "(x)" ["1", "2", "3"]
  • 12. 例: map x [1, 2, 3] f "(x)" ["1", "2", "3"] map([Int], Int -> String) -> [String]
  • 13. 例: map func f(x: Int) -> String { return "(x)" } ! func map(xs: [Int], f: Int -> String) -> [String] { var ys = [String]() for x in xs { ys.append(f(x)) } return ys } ! map([1, 2, 3], f) // ["1", "2", “3"] map([1, 2, 3], { "($0)" }) // ["1", "2", "3"]
  • 14. 例: map Int [Int] f String [String] map([Int], Int -> String) -> [String]
  • 15. 例: map T [T] T -> U U [U] map([T], T -> U) -> [U]
  • 16. 例: map func map<T, U>(xs: [T], f: T -> U) -> [U] { var ys = [U]() for x in xs { ys.append(f(x)) } return ys } ! // [Int] -> [String] map([1, 2, 3], { "($0)" }) // ["1", "2", "3"] // [Int] -> [Double] map([1, 2, 3], { $0 * 2.0 }) // [2.0, 4.0, 6.0] // [Double] -> [CGRect] map([1, 2, 3], { CGRect(x: $0, y: $0, width: 100.0, height: 100.0) })
  • 17. クラスの例: Stack class Stack<T> { private var array = [T]() func push(item: T) { array.append(item) } func pop() -> T { return array.removeLast() } } ! let stack = Stack<Int>() stack.push(1) stack.push(2) stack.push(3) stack.pop() // 3 stack.pop() // 2 stack.pop() // 1
  • 19. Enums enum BloodType { case A, B, O, AB } ! struct Person { var bloodType: BloodType } ! var p = Person(bloodType: BloodType.A) var q = Person(bloodType: .A) q.bloodType = .AB
  • 20. Enums • ObjCのEnumと違って、「値」を持たない • ex. 東西南北に整数を割り当てる意味? • 従来通りに値を持たせることもできる • 文字列もOK
  • 21. …with associated values /// ダイアログのUI要素を指定するenum。 enum DialogItem { case TextButton(title: String, identifier: String) case GrayButton(title: String, identifier: String) case Text(String) case Title(String) case Margin(CGFloat) case Group([DialogItem]) } ! let item1 = DialogItem.Margin(20) let item2 = DialogItem.Text("String")
  • 22. Associated Values • enumの各状態に値を紐づけることができる • 型が違っていてもいい • 単なる列挙というよりは、「複数の型のどれ か」を表す型になる
  • 23. Switchで値を展開 switch item { case let .Title(title): println("Title: (title)") case let .Text(text): println("Text: (text)") case let .TextButton(title: title, identifier: identifier): /// case let .GrayButton(title: title, identifier: identifier): /// case let .Group(subitems): /// default: break }
  • 24. 例: DialogViewController let items: [DialogViewController.DialogItem] = [ .Title("ダイアログ"), .Text("表示要素を配列で渡すだけで、自在にダイアログを作ることができます。"), .TextButton(title: "ボタン", identifier: "button1"), .Margin(60), .Group([ .Group([.Text("二段組み"), .Text("にも")]), .Group([.Text("対応"), .Text("(たぶん)")]) ]), .Group([ .TextButton(title: "ボタン", identifier: "button2"), .GrayButton(title: "ボタン", identifier: "button3"), .TextButton(title: "ボタン", identifier: "button4") ]) ] let dialog = DialogViewController(items: items, callback: nil) presentViewController(dialog, animated: true, completion: nil)
  • 25. 簡単な例: Failable • 「失敗するかもしれない」結果を記述する • 失敗すればFailed、成功すればSucceeded • 成功した場合は結果をAssociated Valueに持 つ
  • 26. 例: Failable<T> enum Failable<T> { case Succeeded(T) // 成功したときの値 case Failed // 失敗フラグ init(_ value: T) { self = .Succeeded(value) } }
  • 27. 例: Failable<T> // 2で割れたら割るけど割れなかったらあきらめる(やる気のない)関数 func failableHalve(x: Int) -> Failable<Int> { if x % 2 == 0 { return .Succeeded(x / 2) } else { return .Failed } } ! switch failableHalve(12) { case let .Succeeded(r): println("Answer: (r)") default: println("Odd Number") }
  • 28. それって // 2で割れたら割るけど割れなかったらあきらめる(やる気のない)関数 func failableHalve(x: Int) -> Optional<Int> { if x % 2 == 0 { return .Some(x / 2) } else { return .None } } ! switch failableHalve(12) { case let .Some(r): println("Answer: (r)") default: println("Odd Number") }
  • 29. Optionalなのでは? // 2で割れたら割るけど割れなかったらあきらめる(やる気のない)関数 func failableHalve(x: Int) -> Int? { if x % 2 == 0 { return x / 2 } else { return nil } } !! if let r = failableHalve(12) { println("Answer: (r)") } else { println("Odd Number") }
  • 32. Optional以前 • オブジェクトとはポインタである • 特別なアドレス(多くの場合0)をNULLと呼 び、そこを指すポインタを「無効なオブジェ クト」として扱う
  • 33. 問題点 • NULLを無効な値だと知っているのは実行中のプ ログラムとプログラマだけ • コンパイラには他のポインタ値と区別できない • →実行時に落ちる • 予期せぬNULLが紛れ込まないように「気をつけ る」「確認する」ことしかできなかった
  • 34. Optionalのいいところ • 「無効な値」という概念を型にしたことで、 意味論ではなく構文論として扱える • 無効な値を扱う操作が「書けない」文法
  • 35. Optional<T> enum Optional<T> : Reflectable, NilLiteralConvertible { case None case Some(T) ! /// Construct a `nil` instance. init() ! /// Construct a non- `nil` instance that stores `some`. init(_ some: T) ! /// If `self == nil`, returns `nil`. Otherwise, returns `f(self!)`. func map<U>(f: (T) -> U) -> U? ! /// Returns a mirror that reflects `self`. func getMirror() -> MirrorType ! /// Create an instance initialized with `nil`. init(nilLiteral: ()) }
  • 36. Optional<T> • 実体はGeneric Enum • 実はちょっと嘘で、特別扱いを受けている • cf. http://qiita.com/koher/items/ 5dd6ce7427e7ecff4249 • (Failable<T>と同じように)箱です
  • 37. Optional as 箱 • 「Tかもしれない」ではなく、「Tの入る箱」 • 値に触るためには箱を開ける必要がある • binding/coalescing/unwrapping • 箱を開けずに操作する方法もある • mapping/chaining
  • 38. Optional Binding var optionalInt: Int? ! if let int = optionalInt { // int: Int println("optionalInt was (int)") } else { println("optionalInt was nil") } ! var array = [1, 2, 3, 4] while let item = array.last { // item: Int println("(item)") array.removeLast() }
  • 39. 箱を開ける: Optional Binding • 値があればtrueに評価されつつ中身を変数に 束縛(bind)してくれる • 一度に一個しかbindできないのは多少不便
  • 40. Optional Coalescing optionalInt ?? 3 ! // ↓と等価: optionalInt != nil ? optionalInt! : 3 ! // あるいは: func coalesce<T>(lhs: T?, rhs: @autoclosure () -> T) -> T { if let lhs = lhs { return lhs } else { return rhs() } } coalesce(optionalInt, 3)
  • 41. 箱を開ける: Optional Coalescing • 開けられたら開ける • 開けられなかったら開けない • かわりにデフォルト値を返す
  • 42. 無理矢理開ける: Forced Unwrapping optionalInt! • 値があればそれが返るが、なければ落ちる • 落ちる可能性があるので使うべきではない • 安全が保証できるなら構わないが……
  • 43. 箱から出さずに進める方法 • Optional mapping • Optional chaining
  • 44. Optional Mapping /// 3倍する関数 func triple(x: Int) -> Int { return x * 3 } ! optionalInt = 2 // 以下はすべて.Some 6 optionalInt.map(triple) map(optionalInt, triple) optionalInt.map({ $0 * 3 })
  • 45. 箱を開けない: Optional Mapping • 箱の中から別の箱の中へ • 値があればそれを移して別の箱(Optional) を作る • nilならばnilを返す
  • 46. Optional Mapping T U T -> U T? U? map(T?, T -> U) -> U?
  • 47. Optional Chaining class A { var b: B? } ! class B { var c: C? } ! class C { var i: Int = 1 } var a: A? = A() // a.b.c.iにアクセスしたい
  • 48. Optional Chaining var a: A? ! if let a = a { if let b = a.b { if let c = b.c { println("We finally find (c.i)!") } } }
  • 49. Optional Chaining var a: A? ! if let i = a?.b?.c?.i { println("Optional chaining makes (i)t easy.") }
  • 50. 箱を開けない: Optional Chaining • 失敗するかもしれない呼び出しを連鎖できる • 失敗すればその先には進まずnil
  • 51. Optional Chaining a?.b?.c?.i A? aはA?型の変数
  • 52. × Optional Chaining a.b A? A?型にbというメンバはない
  • 53. Optional Chaining a?.b?.c?.i A? a?.bという形にする
  • 54. Optional Chaining a?.b?.c?.i A() or nil aはnilかSomeのどちらか
  • 55. Optional Chaining a?.b?.c?.i A() B? or nil Someならばbに触れる
  • 56. Optional Chaining a?.b?.c?.i A() B? or nil nil nilならそれで終わり
  • 57. Optional Chaining a?.b?.c?.i A() B? or nil nil bはB?型の変数
  • 58. Optional Chaining a?.b?.c?.i A() B() C? or or nil nil nil 同じように分岐
  • 59. Optional Chaining a?.b?.c?.i A() B() C() 7 or or or nil nil nil nil 以下同文
  • 60. 書き直してみる extension Optional { func chain<U>(f: T -> U?) -> U? { if let s = self { return f(s) } else { return nil } } } ! if let i = a.chain({ $0.b }).chain({ $0.c }).chain({ $0.i }) { println("(i)") } ! // (正確には↓だが説明は省略(結果は等しくなる)) // let k = a.chain({ $0.b.chain({ $0.c.chain({ $0.i }) }) })
  • 62. Failable Halve Int Int? // 2で割れたら割るけど割れなかったらあきらめる(やる気のない)関数 func failableHalve(x: Int) -> Int? { if x % 2 == 0 { return x / 2 } else { return nil } } ! if let a = failableHalve(x) { println("Halve((x)) = (a)") } else { println("Failed") }
  • 63. Failable Halve Again Int Int? if let a = failableHalve(x) { if let b = failableHalve(a) { println("Halve^2((x)) = (b)") } else { println("Failed") } } else { println("Failed") } Int Int?
  • 64. Failable Halve The 3rd Int Int? if let a = failableHalve(x) { if let b = failableHalve(a) { if let c = failableHalve(b) { println("Halve^3((x)) = (c)") } else { println("Failed") } } else { println("Failed") } } else { println("Failed") } Int Int? Int Int?
  • 65. Failable Halve Chaining Int Int? if let a = failableHalve(x).chain(failableHalve).chain(failableHalve) { println("Halve^3((x)) = (a)") } else { println("Failed") } Int? Int?
  • 66. Failable Halve Chaining Int Int? Int? Int? 24 failableHalve(24) // Some 12 failableHalve(24).chain(failableHalve) // Some 6 failableHalve(24).chain(failableHalve).chain(failableHalve) // Some 3 failableHalve(24).chain(failableHalve).chain(failableHalve).chain(failableHalve) // nil ! 36 failableHalve(36) // Some 18 failableHalve(36).chain(failableHalve) // Some 9 failableHalve(36).chain(failableHalve).chain(failableHalve) // nil failableHalve(36).chain(failableHalve).chain(failableHalve).chain(failableHalve) // nil
  • 68. Optional Chaining T f U? f(t): U?
  • 69. Optional Chaining U g V? T f U? f(t): U?
  • 70. Optional Chaining g f V? T U? f(t).chain(g): V?
  • 71. Optional Chaining g V h W? f V? T U? f(t).chain(g): V?
  • 72. Optional Chaining g h W? f V? T U? f(t).chain(g).chain(h): W?
  • 74. Array Mapping T [T] T -> U U [U] map([T], T -> U) -> [U]
  • 75. Optional Mapping T U T -> U T? U? map( T?, T -> U) -> U?
  • 76. Optional<T>とArray<T> • T型の値が入った箱 • mapを使えば箱の中身だけを写すことができ る
  • 77. Optional as 状況 • ところで、Optionalは「nilかもしれない」と いう状況(context)を表現していた • Arrayはどんな状況を表現している? • →「値が確定していない」
  • 80. 歩く (0, 1) (-1,0) (1, 0) (0,-1) Kyoto
  • 81. 歩く /// 座標 typealias Position = (Int, Int) ! /// 東西南北のどこかへ歩きます func walk(from: Position) -> [Position] { let (x, y) = from return [(x - 1, y), (x + 1, y), (x, y - 1), (x, y + 1)] } ! walk((0, 0)) // [(-1, 0), (1, 0), (0, -1), (0, 1)]
  • 84. Array Chaining T [U] U [V] V [W]
  • 85. Array Chaining extension Array { func chain<U>(f: Element -> [U]) -> [U] { var ys = [U]() for x in self { ys += f(x) } return ys } } ! walk((0, 0)).chain(walk).chain(walk)
  • 87.
  • 88. BFTask doHeavyJobAsync1().continueWithBlock { (task: BFTask!) -> BFTask in let result = task.result as NSString self.resultLabel1.text = result self.resultLabel2.text = "処理中..." return self.doHeavyJobAsync2(result) }.continueWithBlock { (task: BFTask!) -> BFTask in let result = task.result as NSString self.resultLabel2.text = result self.resultLabel3.text = "処理中..." return self.doHeavyJobAsync3(result) }.continueWithBlock { (task: BFTask!) -> AnyObject! in let result = task.result as NSString self.resultLabel3.text = result return nil }
  • 89. BFTask private func doHeavyJobAsync2(prevResult: String) -> BFTask { var completionSource = BFTaskCompletionSource() // 5秒待ちの処理 // 実用的には、AFNetworkingのcompletionブロック等でsetResultするイメージ Util.delay(5, { completionSource.setResult(prevResult + "オワタ") }) return completionSource.task }
  • 90. Task<T> class Task<T: AnyObject> { private let task: BFTask ! init(task: BFTask) { self.task = task } var result: T? { return task.result as? T } func chain<U: AnyObject>(f: (T -> Task<U>)) -> Task<U> { let newTask = task.continueWithBlock { f($0.result as T).task } return Task<U>(task: newTask) } }
  • 91. Taskを返す関数 private func doHeavyJobAsync2(prevResult: NSString) -> Task<NSString> { let source = Source<NSString>() // 5秒待ちの処理 // 実用的には、AFNetworkingのcompletionブロック等でsetResultするイメージ delay(5, { source.setResult(prevResult + "オワタ" as NSString) }) return source.task }
  • 92. Task Chaining T U U V V W 非同期 非同期 非同期
  • 93. Task Chaining func heavyTask1(Void) -> Task<NSString> { return delayedTask(5) { NSLog("First Task (no params)") return "123" as NSString } } ! func heavyTask2(string: NSString) -> Task<NSNumber> { return delayedTask(5) { NSLog("Second Task (param: (string))") return NSNumber(integer: (string as String).toInt() ?? 0) } } ! func heavyTask3(number: NSNumber) -> Task<NSNumber> { return delayedTask(5) { NSLog("Third Task (param: (number))") return NSNumber(integer: number.integerValue * 2) } }
  • 94. Task Chaining NSLog("Start") heavyTask1().chain(heavyTask2).chain(heavyTask3) NSLog("End") 2014-11-27 21:15:24.659 MySweetSwift[18362:314049] Start 2014-11-27 21:15:24.663 MySweetSwift[18362:314049] End 2014-11-27 21:15:29.663 MySweetSwift[18362:314049] First Task (no params) 2014-11-27 21:15:35.136 MySweetSwift[18362:314049] Second Task (param: 123) 2014-11-27 21:15:40.636 MySweetSwift[18362:314049] Third Task (param: 123)
  • 95. まとめ • Optionalはかわいい! • ArrayとOptionalは似ている • すなわち、箱であり、状況である • 非同期処理も同じように見ることができる • Optional Chainingのような書きかたができて、そ れはBFTaskに似ている