Getting started functional programming?
Swift
Yuichi Yoshida
Chief engineer, DENSO IT Laboratory, Inc.
#yidev
@sonson_twit
© 2014YuichiYoshida, All rights reserved. Redistribution or public display not permitted without written permission from YuichiYoshida.
Swiftで多層型で戻り値を返すことの是非と雑談
自己紹介
2tchの中の人
• iOS好きです
• 2tch(2ちゃんねるビューア)
• iOS SDK Hacksなど
• 研究・開発
• コンピュータビジョン
• 機械学習
• 画像検索サービスとか
• 車向けサービスやハードウェアとか
今日のお話
• 2ちゃんねるアプリに対するAppleとGoogleの反応か
ら見る審査の傾向
• Swiftでfunctional programmingっぽいことを始めた
1ヶ月以上の審査はなんだったのか
• 基本Hなのはいけないと思います
• 下品なのはいけないと思います
• 口汚いのはいけないと思います
• 個人(公人)への悪口はいけないと思います
• リンクもいけないと思います
• 下品なAAもいけないと思います
2ch, むしろインターネット全否定
弱り目にたたり目
• AdMob(Google)からもリジェクト
• 2tch,下ネタとか多いから排除するわ
• むしろ,Appleより厳しい状況だった
もうだめぽ
• アメリカの人は2chが生理的に受け付けないっぽい
• もしかすると広告方面からの圧力?
• Androidでも2ちゃん関係のアプリが落ちたとか?
• 類推できるけど,もう不毛なので・・・
ææææææ æ æ æ æ æ æ øÇÇ * * ]
ææ æ *, +┬gÕgÇ,]ææ æ Ü^*Ç*Ç*Ç*Ç*,ø%ø
,ææ -æ æ z z ,z;”;Çæ]]l-›æt|‹ z
ææ j,æææ l l jæ››ydflミ”* *Ü≪8jdÕgææææææもういい·«
æ‹–,ææ ßÄ*¢ÇÄ,j´¤g—zpé|p〉〉¡こjレ%
-æ æ À–--z ¢Ç–lêz z-zy王王王王{¢Ç
zæææ æ レ§z j§“冫 j J]* * *é* * * *]Åö‰øææææもう·
–æææ ]]zŸJz┴Õé–>%Õ—二三シ´››
æ*“*‹æ ,{二二二二二二二二二l–,æ – ›æææ休めっ·«
j-æz¢Ç,‹´›ææææææææ æ æ zz,æレ%´ŒÀ–
ææzzæ æ æ Ç›æææææ æ æ æ zz, -æææ æ 8z
ææzzæz,j jº ,zi z–'æææææææææ zj-ææ æ æ -ææ休めっ·«
ææzzæ^´'S%Hæææææææææææ-+─æææ*ê,z
ææzzææ æ œææææææææ æ -+─æææ- –zæææqmlqmlっ·«
ææzzæ p¤+º;っÀ–*,++p+─ %% ´ŒÀ–ææ -ææ {
ææzz,æy三二æ æ zæ│æææææææææ -ææ -
ææzz,æ —˛++一%^Ÿ“æææææ æ ]*, く æ ノz
ってみんなに言われた
reddift
Swift Reddit API Wrapper
reddift
Swift Reddit API Wrapper
• 1億人以上のアメリカのSNS
• APIあり
• Objective-CのAPI Wrapperはあり
• OAuth2に対応してない
• Swiftじゃない
• よし,いっちょ,勉強がてら作るか!
• MIT License
https://github.com/sonsongithub/reddift
OAuth2ベース
Don’t pass your password to anyone.
• OAuth周りのコードも同梱
• 岸川さんのKeychainAccessで管理
• 複数アカウントも対応
Swift impression
Optional sucks?
• Optionalに耐えられない
• Storyboardと相性が悪過ぎる
• というかUIベースのコードと相性悪すぎ
• コードがif let hoge = hoge{}であふれる
• エラー処理と戻り値
• 処理がネストして汚い
Slackにて
Getting started functional programming
• 岸川大先生より
• Efficient JSON in Swift with Functional Concepts and Generics
を読め
• Functional programmingベースのコードを書け
• くっそきたないコード書いてんじゃねーよ!!!

• と言われなかったけど,勉強のポインタを教えてもらった
• 早速,勉強を始めてみた
よくあるコード?
func linkList(
paginator:Paginator?,
sortingType:ListingSortType,
subreddit:Subreddit?,
completion:(
links:[Link],
paginator:Paginator?,
error:NSError?
)->Void) -> NSURLSessionDataTask
ダウンロード後のコールバックをブロックで渡す
書き方もありますが
func linkList(paginator:Paginator?, sortingType:ListingSortType, subreddit:Subreddit?, completion:(links:[Link], paginator:Paginator?, error:NSError?)->Void)
-> NSURLSessionDataTask {
var parameter:[String:String] = [:]
if let paginator = paginator {
if paginator.sortingType == sortingType {
parameter = paginator.parameters()
}
}
var path = sortingType.path()
if let subreddit = subreddit {
path = "/r/(subreddit.display_name)(path)"
}
var URLRequest = NSMutableURLRequest.mutableOAuthRequestWithBaseURL(baseURL, path:path, parameter:parameter, method:"GET", token:token)
let task = URLSession.dataTaskWithRequest(URLRequest, completionHandler: { (data:NSData!, response:NSURLResponse!, error:NSError!) -> Void in
self.updateRateLimitWithURLResponse(response)
if error != nil {
dispatch_async(dispatch_get_main_queue(), { () -> Void in
completion(links:[], paginator: nil, error: error)
})
}
else {
if let json:[String:AnyObject] = NSJSONSerialization.JSONObjectWithData(data, options:NSJSONReadingOptions.allZeros, error: nil) as?
[String:AnyObject] {
let (links, paginator) = self.parseLinkListJSON(json)
if links.count > 0 && paginator != nil {
paginator?.sortingType = sortingType;
dispatch_async(dispatch_get_main_queue(), { () -> Void in
completion(links:links, paginator:paginator, error:nil)
})
}
else {
dispatch_async(dispatch_get_main_queue(), { () -> Void in
completion(links:links, paginator:paginator, error:NSError.errorWithCode(0, userinfo: ["error":"Can not get any contents
expectedly."]))
})
}
}
else {
dispatch_async(dispatch_get_main_queue(), { () -> Void in
completion(links:[], paginator: nil, error:NSError.errorWithCode(0, userinfo: ["error":"Can not parse response object."]))
})
}
}
})
task.resume()
return task
}
エラーと戻り値がぐちゃぐちゃに
戻り値をResult<T>にする
public enum Result<A> {
case Success(Box<A>)
case Failure(NSError)
public init(value:A) {
self = .Success(Box(value))
}
public init(error: NSError) {
self = .Failure(error)
}
........
}
public final class Box<A> {
public let value: A
public init(_ value: A) {
self.value = value
}
}
正しい戻り値か,

Errorオブジェクトのどちらかになる
enum
swiftがenumに自由なオブジェクトを
放り込めないのでGenericsで逃げる
戻り値へのアクセスのイメージ
(a : Result<Hoge>) -> Void {
switch(a) {
case let .Success(x):
println(x.value)
case let .Failuare(x):
println(x.error)
}
}
戻り値がenumのSuccessに当たれば,

xが宣言されて,x.valueを使う
戻り値がenumのFailurareに当たれば,

xが宣言されて,x.valueを使う
これでswitchで中身がどんな結果でも統一して,エラーと戻り値の
ハンドリングをResult<T>できるようになる
さらにコードを綺麗にすると
infix operator >>> { associativity left precedence 150 }
public func >>><A, B>(a: Result<A>, f: A -> Result<B>) -> Result<B>
{
switch a {
case let .Success(x):
return f(x.value)
case let .Failure(error):
return .Failure(error)
}
}
Resultから値を取る演算子を定義すると,メソッドチェーンぽくもかける
コードはさらにすっきり
var request =
NSMutableURLRequest.mutableOAuthRequestWithBaseURL(Session.baseURL, path:"/api/
v1/me", method:"GET", token:token)
let task = URLSession.dataTaskWithRequest(request, completionHandler:
{ (data:NSData!, response:NSURLResponse!, error:NSError!) -> Void in
let responseResult = resultFromOptionalError(Response(data: data,
urlResponse: response), error)
let result = responseResult >>> parseResponse >>> decodeJSON >>>
parseThing_t2_JSON
completion(result)
})
task.resume()
return task
これが果たしていいコードなのか
Result<T>は是か非か
functional programming?
• コードは短い
• いいのか
• 読めない
• 他にも書き方はある
• flatMap
• Optional
• メソッドチェーンやりはじめると,Reactとか?
• 車輪の再発明が多すぎる
• フレームワーク毎に同じようなコードが
• Haskellほど綺麗に書けないのが嫌な感じ
まとめ
• 審査について
• エロへの締めつけ
• GoogleもAppleも
• Swift
• 多相型
• Result<T>
• 演算子定義はいいのか? >>>
デンソーアイティーラボラトリでは、
         研究者,エンジニアを絶賛募集中です。
興味のある方はこちら。https://www.d-itlab.co.jp/recruit/
画像処理・機械学習・信号処理・自然言語処理など

Swiftで多層型で戻り値を返すことの是非と雑談