やさしいiteratee入門
DESCRIPTION
できるだけわかりやすくIterateeを説明します。TRANSCRIPT
やさしいIteratee入門
Play Framework 2 Meetup@kawachi
2014/5/24
データ分析関連書籍翻訳やってます。
Scala, Play, iOS,Ruby, Rails,
Java, C, Python, Javascript, Haxe etc.
Scala, Play 関連2011年 プロトタイプ作成にPlay! 1 採用
(少しだけ)
2012年~ Scalaをメインとして使用
2013年末~ Play 2 で開発
サービス課題をサクッとチェック 事前登録受付中 http://logbook.strikingly.com/
Logbook
ScalaMatsuri
9月6~7日
日本最大のScala Conference
ただいまSponsor募集中!
http://scalamatsuri.org
対象• 今日の話は Play 2.3.0-RC1 を基にしています
• Scala です
• えーと、Java の方いらっしゃいますか?
今日の内容1. Iteratee の概要
2. Iteratee 3つの特徴
3. 身近な Iteratee
Iteratee?• Websocket の説明を読んでいると突然出てくるアレ
• マニュアル内 Advanced topics の最初の項目
• 純粋関数型世界からきた概念
• 2008年に提唱された
• http://okmij.org/ftp/Streams.html
Iteratee を知っておくべき理由• WebSocket/Comet の実装に必要
• Play のいろんなところで使われている
• わかんないと気持ち悪い (ですよね?)
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
今日の目的
Iteratee のイメージをつかむ。
Iteratee が出てきた時に驚かない体を作る。
ストリーミングモデル
読み込み /生成
処理出力 結果
Iteratee
Input (小分けしたデータ)
Enumerator
ストリーミングモデル
読み込み /生成 処理
出力 結果
IterateeEnumerator
変換
Enumeratee
Input (小分けしたデータ)
Iteratee の状態と状態遷移
• Cont — 引き続き Input[E] を処理する
• Done — 結果がでた
• Error — エラーが起きた
Inputをひとつ処理する毎に 状態遷移
Cont
Done Error
Iteratee は状態をもつ
Iteratee ライブラリの3大要素play.api.libs.iteratee
Iteratee
Enumerator
Enumeratee
今日の内容1. Iteratee の概要
2. Iteratee 3つの特徴
3. 身近な Iteratee
3つの特徴• Immutable
• Non-blocking
• Composable
Immutable?
でも状態があるよ? Immutable で状態を変更するには… Immutable collection を思い出してみよう。 !
val a1 = List(1, 2, 3) val a2 = a1 ++ List(4, 5, 6)
もとのa1は変更されずそのまま。 新しい collection が生成される。
Immutable!Cont 状態の Iteratee は Input を引数にとって 次の Iteratee を返す
関数をもつ
1 Input 毎に 別の Iteratee が
生成される
Done か Error になったら それ以上入力を受け取らない
Cont
Cont
Done
コード見たほうが分かりやすい?
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] }
Non-blockingIterateeEnumerator
Iteratee
Iteratee
…
Iteratee に Input を流し込み、将来の Iteratee を得る trait Enumerator[E] { def apply[A](i: Iteratee[E, A]): Future[Iteratee[E, A]] }
blockしない
混乱しがちなこと• Iteratee には
状態がわかっているもの (StepIteratee)と、
将来状態がわかるもの(FutureIteratee)がある
• Future[Iteratee] は
Iteratee (FutureIteratee) に
変換できる (Iteratee.flatten())
Iteratee
StepIteratee FutureIteratee
Enumerator.apply() の結果は
Iteratee とみなせる
IterateeEnumerator
Iteratee (FutureIteratee)
Iteratee.flatten()
結果Aの計算も Non-blocking
IterateeEnumerator
Iteratee
Iteratee
…
A
trait Iteratee { def run: Future[A] }
blockしない
Composable
• 小さなコンポーネントを組み合せてより大きなコンポーネントをつくること
Enumerator.apply(Iteratee)
Iteratee[E,A]E
Enumerator[E]
Iteratee[E,A] (FutureIteratee)
Iteratee.flatten()
EA
AE E
|>>
Enumeratee.compose(Enumeratee)
Enumeratee[B,C]
AEnumeratee[A,B]
A B B C C
Enumeratee[A,C]A A C C
><>
Enumerator.through(Enumeratee)
Enumeratee[A,B]
AEnumerator[A]
A B B
Enumerator[B]
B B
&>
Enumeratee.transform(Iteratee)
Iteratee[B,C]
AEnumeratee[A,B]
A B BC
Iteratee[A,C]
A AC
&>>
Enumerator.andThen (Enumerator)
E
Enumerator[E]
EEnumerator[E]
1
2
ひとつめの Enumerator が 終わったら、ふたつめ
Enumerator[E]
E E
>>>
Enumerator.interleave(Enumerator)
E
Enumerator[E]
EEnumerator[E]
ふたつを織り交ぜて出力する
Enumerator[E]E E
>-
記号API
• |>>, |>>|, &>, >-, >>> などの記号がある
• Methodを呼び出しているだけ
• その都度定義をみても大丈夫
例: def |>>[A](i: Iteratee[E, A]): Future[Iteratee[E, A]] = apply(i)
今日の内容1. Iteratee の概要
2. Iteratee 3つの特徴
3. 身近な Iteratee
Iteratee が
Play のどんなところで使われているかみてみましょう
身近な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])
身近なIteratee (WebSocket)
Browser
Play
Enumerator
Iteratee
WebSocket
ここは自分で頑張る
Actor based web socket API
• Play 2.3 から入る
• 自分で頑張る部分を手助けしてくれる
ドキュメント内のサンプルコード def socket = WebSocket.acceptWithActor[String, String] { request => out => MyWebSocketActor.props(out) }
RequestHeaderActorRef (出力担当Actor)
Props (入力担当Actorの設定)
Actor based web socket API
Browser
Play
Enumerator
Iteratee
出力Actor
入力Actor
Props
ここは自分で頑張る
身近なIteratee (Result)
def index = Action { Ok("hello") } !
case class Result( header: ResponseHeader, body: Enumerator[Array[Byte]])
これは Result 型
身近なIteratee (Result)
Browser
Play
EnumeratorHTTP request
身近なIteratee (Result)Ok.chunked() で chunked response が返せる。 送信開始時に全データ Content-Length を知らなくていいから嬉しい(こともある)。 !
def index = Action { Ok.chunked( Enumerator.fromFile(new File("1gb.file"))) }
身近な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
Play身近なIteratee (BodyParser)
BodyParserRequestHeader
Iteratee
Input[Array[Byte]]
①
②A
HTTP request の body を 小分けしたもの
Request.body ができた
③HTTP request
まとめ• Iteratee はストリーミング処理API
• Enumerator → Enumeratee → Iteratee
• Cont, Done, Error 状態をもつ
• Immutable, Non-blocking, Composable
• Play のいろんなところで使われている
ご清聴ありがとうございました
やさしかった…ですね?