yashiganiの英傑になるまで死ねない日記

週末はマスターバイクでハイラルを走り回ります

ぼくのApple Special Event

まとめ

  • iPad Proはでかすぎる
  • iPhone 6sを買う
  • 今回は2時間くらいで終わったけどねむいものはねむい

顧客の欲しかったもの

関西モバイルアプリ研究会で「Swiftで自然数を作るっ」という発表をしました #関モバ

Fondue enchaînéewww.flickr.com

毎月おなじみの関西モバイルアプリ研究会で「Swift自然数を作るっ」という発表でライブコーディングをしました.

kanmoba.connpass.com

書いたコードはgistで公開しています(少し長いので最後に埋め込んであります).

自然数についてはWikipediaの項目を参照してください.

自然数 - Wikipedia

コードだけだとわかりにくいとおもうので少し解説を書きます.

解説コーナー

自然数のデータ構造を作る

例えば,自然数3は以下のように表現できます.

suc(suc(suc(0)))

要は0からはじめて3回後に進んだ状態です. この構造をSwiftで表現すると,

enum N {
    case Zero
    indirect case Succ(N)
    
    static func succ(n: N) -> N {
        return .Succ(n)
    }
}

となります. Swift2で新たに追加されたindirectによって再帰的なenumが作れるようになったので,このような表現が可能です. ちなみに,.Sucでなく.Succにしているのは.Zeroと揃えるためです.

static func succ(n: N) -> N はある自然数の次の自然数を得るための関数です. mutatingは絶対書きたくないので普通の関数にしています.

.Succ(.Succ(.Succ(...))) のようにネストしまくればどんな数でも作れるようになりましたが,さすがに10みたいな値を作るのは難しいのでヘルパ用意します.

extension N {
    init(from: UInt) {
        self = Repeat(count: Int(from), repeatedValue: N.succ).reduce(.Zero) { $1($0) }
    }
}

負の値が入力されるとinit?にする必要があって面倒なので,ズルしてfrom: UIntにします. fromの回数ぶん.Succで囲えばいいので,長さfromで中身が全部N.succの配列を用意して,.Zeroに当てはめます. 要はこれと同じです.

var n: N = .Zero
for (var i = 0; i < from; i++) {
  n = N.succ(n)
}
self = n

同値,順序

これだけだと正しく実装できているのか証明できないので同値と順序を実装します. SwiftではEquatableComparableプロトコルがそれに当たりますね. 最低Equatableではfunc ==(_:_:) -> Boolを,Comparableではfunc <(_:_:) -> Boolを実装する必要があります. (これだけで==!=<<=>>=が使えるようになります)

extension N: Equatable, Comparable {}

func ==(lhs: N, rhs: N) -> Bool {
    switch (lhs, rhs) {
    case (.Zero, .Zero): return true
    case let (.Succ(a), .Succ(b)): return a == b
    default: return false
    }
}

func <(lhs: N, rhs: N) -> Bool {
    switch (lhs, rhs) {
    case (.Zero, .Succ(_)): return true
    case let (.Succ(a), .Succ(b)): return a < b
    default: return false
    }
}

==は両辺共に.Zeroなら真,共に.Succなら中の値で再帰,それ以外は偽です. <も同様で,左辺が.Zeroで右辺が.Succなら真,両辺共に.Succなら中の値で再帰,それ以外は偽です. 単純なパターンマッチで実装できますね.

加法・乗法

定義に従って,

func +(lhs: N, rhs: N) -> N {
    switch (lhs, rhs) {
    case (let a, .Zero): return a
    case let (a, .Succ(b)): return .Succ(a + b)
    }
}

func *(lhs: N, rhs: N) -> N {
    switch (lhs, rhs) {
    case (_, .Zero): return .Zero
    case let (a, .Succ(b)): return a * b + a
    }
}

ここも単純なパターンマッチで実装できます. 定義をすごく綺麗に実装に落とし込めるので非常に気持ちがいいです.

おまけ

playgroundなどの出力がこのようになって少し見にくいです.

let two: N = .Succ(.Succ(.Zero)))  // => Succ(N.Succ(N.Zero)

CustomLiteralConvertibleを実装すると整形できます.

extension N: CustomStringConvertible {
    var description: String {
        func toInt(n: N) -> Int {
            switch n {
            case .Zero: return 0
            case let .Succ(a): return 1 + toInt(a)
            }
        }
        return "\(toInt(self))"
    }
}

反省

LTなのに15分かかった.

まとめ

enumで簡単に再帰的データ構造が書けるようになって最高ですね!

gist.github.com

Lazy stored propertyについて発表しました #関モバ

この間の関西モバイルアプリ研究会#4でLazy stored propertyについて発表しました.

speakerdeck.com

Lazy stored propertyについて大まかな使いドコロと,テスタブルな設計をする際にこいつを使うと依存の注入に使いやすいのではないか,というアイディアについて話しました. 簡単にまとめると,Lazy stored propertyを使えば,初めてアクセスするときまでインスタンスの生成が遅延されるので,それまでにテストの準備ができるよねということです. lazy は最もすきなキーワードなのでめっちゃオススメです!

追記

Twitterで@さんと@さんにimplicitly unwrapped optionalなpropertyをlazyにしたときにnilを代入することで再度初期化処理が走ることを教えていただきました. こういうかんじです.

gist.github.com

optionalの場合は再度初期化されることはありません. ドキュメントにもこういう動作するという記載は特に見つからないので,実装の都合で動作を騙せるのかもしれません.

iOSアプリのコードレビューについて話しました #関モバ

関西モバイルアプリ研究会#2で「iOSアプリのコードレビューで最近気になるところ」という発表をしました.

kanmoba.connpass.com

コードレビューでよく指摘するようなことをまとめたのですが,まとめてみるとアプリを設計・実装するときに注意すべきこととほとんど変わらないような気がしました. けどコードレビューって言っておいたほうが意識高そうな感じがするのでコードレビューということにしています.

speakerdeck.com

スライドだけ見てもあんまりわかんないとおもったけど,ブクマ集まってるわりに特に質問とか無いので特に補足はしません. 代わりにコードレビューのコツっぽいのをつけておきます.

コードレビューするときに最近ちょっと気にしてること

ちょっと気にしていることを書いておきます. 筆者の経験に基づくポイントです.

1. 理由を聞く

こうしてください!って指摘するよりは理由を聞くようにしています. スライドの例を使うと,「この値はstoryboardで設定してください!」というよりは「この値もstoryboardで設定できますが,コードで設定している理由はありますか?」みたいな感じです(これはこれで誘導しすぎですけど).

ピアレビューを続けていると普通相手も自分のレビュー方針みたいなのを自然に学びます. なので,にも関わらずそう実装されているのはなにがしかの理由があるはずですし,だいたいそういうときは悩んだ末の結果なので議論につながるのでより良い実装になることが多いです.

2. ほめる

いいとおもったところはイイネとかポジティブな感想を書いたほうがいいです. 指摘ばかりしてると徐々に精神を病んでしまって,攻撃的になります. 相手のためだけでなく,自分のためにもよいところはほめたほうがいい結果になります.

3. 雑談を書く

雑談とわかるように雑談書いておくのはよくやります. 便利なタグは[雑談][感想][nit]です.


関モバの次回はWWDCGoogle I/Oワイワイビールの会になりそうです. 楽しみですね!!!

Cocoa勉強会関西でお役立ちテクニック3連発という発表をしました #cocoa_kansai

先週ですが,毎度開催されている,Cocoa勉強会 #61でお役立ちテクニックを紹介しました. スライドはこちらです.

今回はこれというネタが無くて連発みたいなネタに走ってしまった… 次はなんとかいいネタを用意します.

おもしろかった発表を紹介

熊谷友宏さん「Swiftカジュアルプログラミング(基礎)不変値と可変値」

_ObjectiveCBridgeableを実装してみたという話がおもしろかったです. 例えば,StringとNSStringは暗黙で変換される(Swift 1.2からは少し制限が追加された)秘密とかに迫る感じで非常に興味深い内容でした. スライドも紹介したかったけど見つけられなかった.

matuyuji さん「Visual Format Languageを簡単に書けるSwiftライブラリyavfl」

発表スライドを見るとわかるとおもうんですが,私はAutoLayoutがだいすきなんです. けれども,VFLはちょっと書きにくくてあまり使っていませんでした. それをカスタムオペレータを使った独自の記法で実現するという内容です. 普段使いにくいなーというVFLをプロダクトに取り入れやすくなりそうですし,実装も独自記法をVFLに変換しているだけなのでプロダクトに採用しやすそうなので今後に注目です.

勉強会後のおたのしみ

ウメヨドでApple Watchを試着してきました. とにかく手元に届くのが待ちきれなくなりました. ちなみに予約したのはApple Watch Sport 38mm ホワイトモデルです.