やさしいiteratee入門

44
やさしいIteratee入門 Play Framework 2 Meetup @kawachi 2014/5/24

Upload: takashi-kawachi

Post on 18-Dec-2014

4.043 views

Category:

Engineering


3 download

DESCRIPTION

できるだけわかりやすくIterateeを説明します。

TRANSCRIPT

Page 1: やさしいIteratee入門

やさしいIteratee入門

Play Framework 2 Meetup@kawachi

2014/5/24

Page 2: やさしいIteratee入門

データ分析関連書籍翻訳やってます。

Scala, Play, iOS,Ruby, Rails,

Java, C, Python, Javascript, Haxe etc.

Page 3: やさしいIteratee入門

Scala, Play 関連2011年 プロトタイプ作成にPlay! 1 採用

(少しだけ)

2012年~ Scalaをメインとして使用

2013年末~ Play 2 で開発

サービス課題をサクッとチェック 事前登録受付中 http://logbook.strikingly.com/

Logbook

Page 4: やさしいIteratee入門

ScalaMatsuri

9月6~7日

日本最大のScala Conference

ただいまSponsor募集中!

http://scalamatsuri.org

Page 5: やさしいIteratee入門

対象• 今日の話は Play 2.3.0-RC1 を基にしています

• Scala です

• えーと、Java の方いらっしゃいますか?

Page 6: やさしいIteratee入門

今日の内容1. Iteratee の概要

2. Iteratee 3つの特徴

3. 身近な Iteratee

Page 7: やさしいIteratee入門

Iteratee?• Websocket の説明を読んでいると突然出てくるアレ

• マニュアル内 Advanced topics の最初の項目

• 純粋関数型世界からきた概念

• 2008年に提唱された

• http://okmij.org/ftp/Streams.html

Page 8: やさしいIteratee入門

Iteratee を知っておくべき理由• WebSocket/Comet の実装に必要

• Play のいろんなところで使われている

• わかんないと気持ち悪い (ですよね?)

Page 9: やさしいIteratee入門

Iteratee を学びたての

James Roper さん曰く (2012/11)• “Well I just learnt iteratees, and although I'm

feeling more and more comfortable with functional programming every day, I still think like an imperative programmer at heart. This made learning iteratees very difficult for me.”

• Typesafe 社で Play の tech lead やってる人も 難しいっていってた

http://jazzy.id.au/default/2012/11/06/iteratees_for_imperative_programmers.html

Page 10: やさしいIteratee入門

今日の目的

Iteratee のイメージをつかむ。

Iteratee が出てきた時に驚かない体を作る。

Page 11: やさしいIteratee入門

ストリーミングモデル

読み込み /生成

処理出力 結果

Iteratee

Input (小分けしたデータ)

Enumerator

Page 12: やさしいIteratee入門

ストリーミングモデル

読み込み /生成 処理

出力 結果

IterateeEnumerator

変換

Enumeratee

Input (小分けしたデータ)

Page 13: やさしいIteratee入門

Iteratee の状態と状態遷移

• Cont — 引き続き Input[E] を処理する

• Done — 結果がでた

• Error — エラーが起きた

Inputをひとつ処理する毎に 状態遷移

Cont

Done Error

Iteratee は状態をもつ

Page 14: やさしいIteratee入門

Iteratee ライブラリの3大要素play.api.libs.iteratee

Iteratee

Enumerator

Enumeratee

Page 15: やさしいIteratee入門

今日の内容1. Iteratee の概要

2. Iteratee 3つの特徴

3. 身近な Iteratee

Page 16: やさしいIteratee入門

3つの特徴• Immutable

• Non-blocking

• Composable

Page 17: やさしいIteratee入門

Immutable?

でも状態があるよ? Immutable で状態を変更するには… Immutable collection を思い出してみよう。 !

val a1 = List(1, 2, 3) val a2 = a1 ++ List(4, 5, 6)

もとのa1は変更されずそのまま。 新しい collection が生成される。

Page 18: やさしいIteratee入門

Immutable!Cont 状態の Iteratee は Input を引数にとって 次の Iteratee を返す

関数をもつ

1 Input 毎に 別の Iteratee が

生成される

Done か Error になったら それ以上入力を受け取らない

Cont

Cont

Done

Page 19: やさしいIteratee入門

コード見たほうが分かりやすい?

sealed trait Step[E, +A] !object Step { case class Done[+A, E](a: A, remaining: Input[E]) extends Step[E, A] case class Cont[E, +A](k: Input[E] => Iteratee[E, A]) extends Step[E, A] case class Error[E](msg: String, input: Input[E]) extends Step[E, Nothing] }

Page 20: やさしいIteratee入門

Non-blockingIterateeEnumerator

Iteratee

Iteratee

Iteratee に Input を流し込み、将来の Iteratee を得る trait Enumerator[E] { def apply[A](i: Iteratee[E, A]): Future[Iteratee[E, A]] }

blockしない

Page 21: やさしいIteratee入門

混乱しがちなこと• Iteratee には

状態がわかっているもの (StepIteratee)と、

将来状態がわかるもの(FutureIteratee)がある

• Future[Iteratee] は

Iteratee (FutureIteratee) に

変換できる (Iteratee.flatten())

Iteratee

StepIteratee FutureIteratee

Page 22: やさしいIteratee入門

Enumerator.apply() の結果は

Iteratee とみなせる

IterateeEnumerator

Iteratee (FutureIteratee)

Iteratee.flatten()

Page 23: やさしいIteratee入門

結果Aの計算も Non-blocking

IterateeEnumerator

Iteratee

Iteratee

A

trait Iteratee { def run: Future[A] }

blockしない

Page 24: やさしいIteratee入門

Composable

• 小さなコンポーネントを組み合せてより大きなコンポーネントをつくること

Page 25: やさしいIteratee入門

Enumerator.apply(Iteratee)

Iteratee[E,A]E

Enumerator[E]

Iteratee[E,A] (FutureIteratee)

Iteratee.flatten()

EA

AE E

|>>

Page 26: やさしいIteratee入門

Enumeratee.compose(Enumeratee)

Enumeratee[B,C]

AEnumeratee[A,B]

A B B C C

Enumeratee[A,C]A A C C

><>

Page 27: やさしいIteratee入門

Enumerator.through(Enumeratee)

Enumeratee[A,B]

AEnumerator[A]

A B B

Enumerator[B]

B B

&>

Page 28: やさしいIteratee入門

Enumeratee.transform(Iteratee)

Iteratee[B,C]

AEnumeratee[A,B]

A B BC

Iteratee[A,C]

A AC

&>>

Page 29: やさしいIteratee入門

Enumerator.andThen (Enumerator)

E

Enumerator[E]

EEnumerator[E]

1

2

ひとつめの Enumerator が 終わったら、ふたつめ

Enumerator[E]

E E

>>>

Page 30: やさしいIteratee入門

Enumerator.interleave(Enumerator)

E

Enumerator[E]

EEnumerator[E]

ふたつを織り交ぜて出力する

Enumerator[E]E E

>-

Page 31: やさしいIteratee入門

記号API

• |>>, |>>|, &>, >-, >>> などの記号がある

• Methodを呼び出しているだけ

• その都度定義をみても大丈夫

例: def |>>[A](i: Iteratee[E, A]): Future[Iteratee[E, A]] = apply(i)

Page 32: やさしいIteratee入門

今日の内容1. Iteratee の概要

2. Iteratee 3つの特徴

3. 身近な Iteratee

Page 33: やさしいIteratee入門

Iteratee が

Play のどんなところで使われているかみてみましょう

Page 34: やさしいIteratee入門

身近なIteratee (WebSocket)ドキュメント内のサンプルコード def socket = WebSocket.using[String] { request => // Log events to the console val in = Iteratee.foreach[String](println).map { _ => println("Disconnected") } // Send a single 'Hello!' message val out = Enumerator("Hello!") (in, out) } (Iteratee[E, _], Enumerator[E])

Page 35: やさしいIteratee入門

身近なIteratee (WebSocket)

Browser

Play

Enumerator

Iteratee

WebSocket

ここは自分で頑張る

Page 36: やさしいIteratee入門

Actor based web socket API

• Play 2.3 から入る

• 自分で頑張る部分を手助けしてくれる

ドキュメント内のサンプルコード def socket = WebSocket.acceptWithActor[String, String] { request => out => MyWebSocketActor.props(out) }

RequestHeaderActorRef (出力担当Actor)

Props (入力担当Actorの設定)

Page 37: やさしいIteratee入門

Actor based web socket API

Browser

Play

Enumerator

Iteratee

出力Actor

入力Actor

Props

ここは自分で頑張る

Page 38: やさしいIteratee入門

身近なIteratee (Result)

def index = Action { Ok("hello") } !

case class Result( header: ResponseHeader, body: Enumerator[Array[Byte]])

これは Result 型

Page 39: やさしいIteratee入門

身近なIteratee (Result)

Browser

Play

EnumeratorHTTP request

Page 40: やさしいIteratee入門

身近なIteratee (Result)Ok.chunked() で chunked response が返せる。 送信開始時に全データ Content-Length を知らなくていいから嬉しい(こともある)。 !

def index = Action { Ok.chunked( Enumerator.fromFile(new File("1gb.file"))) }

Page 41: やさしいIteratee入門

身近なIteratee (BodyParser)

trait BodyParser[A] extends (RequestHeader => Iteratee[Array[Byte], Either[Result, A]])

BodyParser は RequestHeader を取って Iteratee を返す関数

def save = Action(parse.text) { request => Ok("Got: " + request.body) } これが BodyParser。

指定しなければ parse.anyContentparse された body

Page 42: やさしいIteratee入門

Play身近なIteratee (BodyParser)

BodyParserRequestHeader

Iteratee

Input[Array[Byte]]

②A

HTTP request の body を 小分けしたもの

Request.body ができた

③HTTP request

Page 43: やさしいIteratee入門

まとめ• Iteratee はストリーミング処理API

• Enumerator → Enumeratee → Iteratee

• Cont, Done, Error 状態をもつ

• Immutable, Non-blocking, Composable

• Play のいろんなところで使われている

Page 44: やさしいIteratee入門

ご清聴ありがとうございました

やさしかった…ですね?