swift 2 (& lldb) シンポジウム
TRANSCRIPT
Yuichi YoshidaChief engineer, DENSO IT Laboratory, Inc.
@sonson_twit
© 2014 DENSO IT Laboratory, Inc., All rights reserved. Redistribution or public display not permitted without written permission from DENSO IT Laboratory, Inc.
Value type programmingの話もしたい
Programming Swift 2 (& LLDB) シンポジウム
foldrをとにかく速くする
自己紹介2tchの中の人
• iOS好きです • 2tch(2ちゃんねるビューア) • iOS SDK Hacksなど
• 研究・開発 • コンピュータビジョン • 機械学習 • 画像検索サービスとか • 車向けサービスやハードウェアとか
本業
reddiftSwift Reddit API Wrapper
• 1億人以上のアメリカのSNS • APIあり • Objective-CのAPI Wrapperはあり
• OAuth2に対応してない • Swiftじゃない
• よし,いっちょ,趣味+勉強がてら作るか! • MIT License
https://github.com/sonsongithub/reddift
foldrを速くしたい
Haskellにかぶれ中
foldrとfoldl (畳み込み)• Haskellの高階関数の中にfoldl, foldrというものがある • 良く使われるらしい
x + a02
+ a12
+ a22
foldl
foldr x + a22
+ a12
+ a02
使い方~たとえば逆順
— Haskellrev :: [a] -> [a] rev = foldl (\acc x -> x (: (acc-1)) []
— Swiftfunc rev<T>(array:[T]) -> [T] { return array.reduce([]) { (acc:[T], x:T) -> [T] in [x] + acc } }
foldlをSwiftで実装してみよう
foldl = reduce
終了
foldrをSwiftで実装してみよう
foldr = reverse().reduce
終了・・・・・?
遅い
extension CollectionType { func foldr_reduce<T>(accm:T, f: (T, Self.Generator.Element) -> T) -> T { return self.reverse().reduce(accm) { f($0, $1) } }
func foldl_reduce<T>(accm:T, @noescape f: (T, Self.Generator.Element) -> T) -> T { return self.reduce(accm) { f($0, $1) } } }
理由は?• 高階関数で違いが有る?
• 再帰,for, forEach, reduce….
• @noescape • 必要ないのに毎回キャプチャするのが遅い? • 考えにくいけどなぁ
• reverseに何か問題がある • そのまま→速い • reverseする→遅い • 怪しい・・・
実装 - 再帰
// recursive var g = self.generate() func next() -> T { return g.next().map {x in f(x, next())} ?? accm } return next()
Haskellは再帰が愛されてるのに・・・・
すぐにスタックを食いつぶすので使えない
実装 - for
// recursive var result = accm for temp in self.reverse() { result = f(temp, result) } return result
実装 - 新参forEach
// forEach var result = accm self.reverse().forEach { (t) -> () in result = f(t, result) } return result
reverseが怪しい
• @norio_nomuraさんから色々アドバイス • Swiftのコードを眺めていると,色々判明
普通のreverseっぽい
extension SequenceType { /// Return an `Array` containing the elements of `self` in reverse /// order. /// /// Complexity: O(N), where N is the length of `self`. @warn_unused_result public func reverse() -> [Self.Generator.Element] }
発見!O(1)とか書いてる
extension CollectionType where Index : BidirectionalIndexType { /// Return the elements of `self` in reverse order. /// /// - Complexity: O(1) @warn_unused_result public func reverse() -> ReverseCollection<Self> }
extension CollectionType where Index : RandomAccessIndexType { /// Return the elements of `self` in reverse order. /// /// - Complexity: O(1) @warn_unused_result public func reverse() -> ReverseRandomAccessCollection<Self> }
ReverseCollection
/// A Collection that presents the elements of its `Base` collection /// in reverse order. /// /// - Note: This type is the result of `x.reverse()` where `x` is a /// collection having bidirectional indices. /// /// The `reverse()` method is always lazy when applied to a collection /// with bidirectional indices, but does not implicitly confer /// laziness on algorithms applied to its result. In other words, for /// ordinary collections `c` having bidirectional indices: /// /// * `c.reverse()` does not create new storage /// * `c.reverse().map(f)` maps eagerly and returns a new array /// * `c.lazy.reverse().map(f)` maps lazily and returns a `LazyMapCollection` /// /// - See also: `ReverseRandomAccessCollection`
ReverseRandomAccessCollection
/// A Collection that presents the elements of its `Base` collection /// in reverse order. /// /// - Note: This type is the result of `x.reverse()` where `x` is a /// collection having random access indices. /// - See also: `ReverseCollection`
この型にだけextensionを実装してみる
extension CollectionType where Index : RandomAccessIndexType { func foldr_loop2<T>(accm:T, @noescape f: (Self.Generator.Element, T) -> T) -> T { var result = accm for temp in self.reverse() { result = f(temp, result) } return result } func foldr_reduce2<T>(accm:T, @noescape f: (T, Self.Generator.Element) -> T) -> T { return self.reverse().reduce(accm) { f($0, $1) } } func foldr_forEach2<T>(accm:T, @noescape f: (Self.Generator.Element, T) -> T) -> T { var result = accm self.reverse().forEach { (t) -> () in result = f(t, result) } return result } }
結果(線形)
結果(対数)
ベンチマークテスト
• https://github.com/sonsongithub/testFoldr
value or reference
Value type programmingはどこまで?
• ListViewController • ここでコールバックでリストをうけとる
• DetailViewController • ListViewCon.からリストの要素ひとつを受け取る • 詳細表示 • 編集
Pros. and cons.
• Value type. • 権限と役割が明確 • 速い・・・・? • ポインタに慣れきってるとつらい • コードがわかりやすい?とは思えない.
• Reference type. • C型オールドタイプにはわかりやすい • 権限と役割がめちゃくちゃ • たまにデータがめちゃくちゃになる
デンソーアイティーラボラトリでは、 研究者,エンジニアを絶賛募集中です。
興味のある方はこちら。https://www.d-itlab.co.jp/recruit/
画像処理・機械学習・信号処理・自然言語処理など