Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Scalaz-StreamによるFunctional Reactive Programming

4,911 views

Published on

「Reactive System Meetup in 西新宿」資料です。
http://reactive-shinjuku.connpass.com/event/17991/

Published in: Technology

Scalaz-StreamによるFunctional Reactive Programming

  1. 1. scalaz-streamによる! Functional Reactie Programming 2015年年8⽉月18⽇日 Everforth 浅海智晴
  2. 2. 自己紹介 •  1985年年富⼠士通(株)⼊入社 •  UNIXワークステーション/サーバーのOS、分散基盤、Web基盤の開発 に従事 •  2001年年9⽉月に独⽴立立 •  Java, XML, UMLを中⼼心に活動 •  2005年年4⽉月より2007年年3⽉月まで •  稚内北北星学園⼤大学東京サテライト校教授 •  現在 •  (株) 匠BusinessPlace 取締役チーフコンサルタント •  (株) Everforth 取締役CTO •  OSS •  SmartDoc •  Relaxer •  著作 •  上流流⼯工程UMLモデリング(⽇日経BP) •  マインドマップではじめるモデリング講座(翔泳社) •  Relaxer Java/XMLによるWeb開発(ピアソン) •  ぼくらのScala(Softbank Creative)
  3. 3. ApparelCloud  データを一元化することで、多様な情報を、様々なメディア・デバイスを 通じて  消費者に届け、真のCRMを実現する仕組み。 http://www.apparel-cloud.com/
  4. 4. ApparelCloud クーポン    ブランドサイト オンラインストア ブログ ブランド                         アプリ ニュース ブログ ショップ コンテンツ 集計・分析 ダッシュボード 複数メディア・コンテンツを⼀一元管理理し、クオリティの統⼀一と運⽤用コストの低減を実現。 コンテンツを⼆二重三重に登録する必要もなく、データ分析などの⼀一元化も可能。
  5. 5. 関数型プログラミング
  6. 6. 関数型⾔言語の技術マップ 抽象代数学 数理論理学 直感主義命題論理& 自然演繹 単純型付ラムダ計算 純粋関数型言語 命題 型クラス 群論 Hask圏 (プログラム圏) 永続データ構造 関数型言語 手続き型言語 代数的データ型 Curry-Haward対応 オブジェクト 指向言語 証明 述語論理 様相論理 圏論 直積 直和 不変 副作用なし 参照透過性 置換モデル モノイド モナド 型 計算
  7. 7. Scalaz •  https://github.com/scalaz/scalaz •  キャッチフレーズ •  昔: Scalaz: Type Classes and Pure Functional Data Structures for Scala •  今: An extension to the core Scala library for functional programming. http://typelevel.org •  最新の関数型プログラミングを可能にする機能群を Scala向けに⽤用意 •  型クラス •  純粋関数型データ構造 •  Haskellで実績のある機能群をScalaで実現
  8. 8. Pipelineプログラミング(1) def pipeline(x: Int) = h(g(f(x)) def pipeline(x: Option[Int]) = x.map(f).map(g).map(h) def pipeline(x: Int) = x |> f |> g |> h 関数呼び出し Functor Monad def pipeline(x: Option[Int]) = x.flatMap(f).flatMap(g).flatMap(h) def pipeline(x: Option[Int]) = for (a <- f(x); b <- g(a); c <- h(b)) yiled c
  9. 9. Pipelineプログラミング(2) val pipeline = State(f).flatMap(x => State(g(x))).flatMap(x => State(h(x))) pipeline.run(10) val pipeline = for (a <- State(f);b <- State(g(a)); c <- State(h(c))) yield c pipeline.run(10) Monad (インタープリター型) 参考: [FP] パイプライン・プログラミング http://modegramming.blogspot.jp/2015/06/fp.html val pipeline = io.linesR("infile.txt").filter(_.nonEmpty).map(x => s"${x.length}:$x”) pipeline.run.run scalaz-stream (Process Monad)
  10. 10. Stateモナドによるパイプライン State Monad FuncionState Function Function State Value Value Value Value Value Value
  11. 11. Task •  scalaz.concurrent.Task •  TryとFutureを合わせた機能を持つモナド •  ⻑⾧長所 •  Scalazとの親和性 •  利利⽤用シーンに合わせて並列列処理理の使⽤用・⾮非使⽤用を選択でき る •  Futureのようにスレッドを⼤大量量消費しない •  純粋関数型指向のインタフェース(副作⽤用はrunで実⾏行行) •  関数型的な合成可能な部品化 val t: Task[Int] = Task(f(1000)) val i: Int = t.run val i: Int = Task(f(1000)).run
  12. 12. scalaz-‐‑‒stream
  13. 13. The Reactive Manifest •  http://www.reactivemanifesto.org/ •  ⽇日本語訳 •  http://okapies.hateblo.jp/entry/2014/12/03/025921 •  Responsive •  応答性:すぐ応答する •  Resilient •  耐故障性:回復復⼒力力に富む、⽴立立ち直りが早い •  Elastic •  弾⼒力力性:伸縮⾃自在の •  Message Driven •  メッセージ駆動 •  関連: Reactive Streams •  http://www.reactive-streams.org/
  14. 14. Reactiveの実現 Service Cluster CPU Core Function Service Message Message Message Function Function Function Function Function Service Service Service Service Function Reactive Concurrent Parallel Distributed Responsive Resillience Elasticity Message Driven Concurrent Parallel Distributed
  15. 15. Functional Reactive Programmingで実現したいこと •  関数型プログラミングのメリットを享受 •  参照透過性 •  関数による部品化/部品の組⽴立立て •  パイプラインのセマンティクス •  イベント駆動処理理 •  Callback hellの排除 •  ストリーム処理理 •  リソース管理理 •  フロー制御 •  ⼤大規模データ処理理 •  リソース管理理 •  省省メモリ
  16. 16. Functional Reactive Programming の候補 •  RxJava – Scala •  https://github.com/ReactiveX/RxJava •  Observableモナド •  Scalaz Stream •  https://github.com/scalaz/scalaz-stream •  Processモナド •  Akka Streams •  https://typesafe.com/blog/typesafe-announces-akka- streams •  Akka actor
  17. 17. scalaz-stream •  ScalazベースのStreamingライブラリ •  https://github.com/scalaz/scalaz-stream •  ⽤用途 •  ⼊入出⼒力力処理理フレームワーク •  パイプライン •  部品化、部品合成によるロジック記述 •  ⼤大規模データ⼀一括処理理 •  ストリーム処理理 •  Processモナド •  Pull型 (backpressureあり) •  参照透過性:副作⽤用なし •  部品化:パイプラインによる関数の合成 •  リソースの獲得・解放 •  フロー制御 •  状態機械
  18. 18. Processモナド 既存部品 アプリケーション・ロジック リソース管理 トランザクション管理 フロー制御 Function Function Process Monad Process Monad Channel Sink Channel Sink Process Monad
  19. 19. 部品 (ストリーム) •  Process •  Processモナド。 •  Process1 •  データ変換。Processの⼀一種。 •  Sink •  ストリームの終端。副作⽤用あり。Processの⼀一種。 •  Channel •  外部⼊入出⼒力力。Processの⼀一種。 •  Tee •  2つのストリームを合流流(interleave, zipping)。Processの⼀一種。 •  Wye •  2つのストリームを⾮非決定的に合流流。Processの⼀一種。 •  Writer •  ストリームを2本に分割。Processの⼀一種。
  20. 20. 部品 (連携) •  Exchange •  外部システムと連携。 •  Queue •  キュー。 •  書込み⽤用のメソッドを提供。 •  読込み⽤用のProcessモナドを⽣生成。 •  Topic •  pub/sub機能。 •  書込み⽤用のメソッドを提供。 •  書込み⽤用のProcessモナドを⽣生成。 •  読込み⽤用のProcessモナドを⽣生成。
  21. 21. scalaz-streamの⻑⾧長所/短所 •  ⻑⾧長所 •  Scalazと親和性が⾼高い。 •  純粋関数型の範囲で相当のことができる。 •  部品化が容易易。 •  プログラミングが容易易。 •  短所 •  性能が遅いようです。 •  COMPARING AKKA-STREAM AND SCALAZ-STREAM WITH CODE EXAMPLES •  https://softwaremill.com/comparing-akka-stream-scalaz-stream •  (最初に)使い⽅方を把握するのが難しい。 •  ストリームの分岐は関数型の範囲ではできない。 •  Topicを使⽤用して実現。 •  EIP:Content-Based Routingなど。 •  マシンをまたいだストリームは構築できない。
  22. 22. scalaz-streamプログラム val source: Process[Task, String] = io.linesR("infile.txt") val a: Process[Task, String] = source.filter(_.nonEmpty) val b: Process[Task, String] = a.map(x => s"${x.length}:$x") val c: Process[Task, ByteVector] = b.pipe(text.utf8Encode) val sink: Sink[Task, ByteVector] = io.fileChunkW("outfile.txt") val pipeline: Process[Task, Unit] = b.to(sink) val task: Task[Unit] = pipeline.run val result: Unit = task.run io.linesR("infile.txt").filter(_.nonEmpty).map(x => s"${x.length}:$x"). pipe(text.utf8Encode).to(io.fileChunkW("outfile.txt")).run.run
  23. 23. プログラミング例例 •  パイプラインを流流れてくるデータを以下のルールでパ ケット化 •  3つで⼀一つのパケットにする •  パケットにシーケンス番号をつける •  “start”データの前のパケットにエンドマークをつける •  上記アルゴリズムを実現した部品を⼤大規模データ処理理と ストリーミング処理理の両⽅方に適⽤用する 参考: [scalaz-stream] シーケンス番号とエンドマーク http://modegramming.blogspot.jp/2015/03/scalaz-stream.html
  24. 24. 準備 case class Packet(seqno: Int, end: Boolean, content: String) def sink: Sink[Task, Packet] = { io.channel((a: Packet) => Task.delay(println(a))) } 参考: [scalaz-stream] ストリーミングで状態機械 http://modegramming.blogspot.jp/2015/04/scalaz-stream.html 参考: [scalaz-stream] Scala的状態機械/OOP編 http://modegramming.blogspot.jp/2015/03/scalaoop.html 参考: [scalaz-stream] Scala的状態機械/FP編 http://modegramming.blogspot.jp/2015/03/scalafp.html
  25. 25. アプリケーション・ロジック        def buildTextToPacket[M[_]: Monad](source: Process[M, String]): Process[M, Packet] = { source. chunk(3). // 3個ずつチャンク化            pipe(zipWithNext). // 次のパケットを同時に取得            pipe(zipWithIndex). // インデックを採番            map(toPacket) } def toPacket(x: ((Vector[String], Option[Vector[String]]), Int)): Packet = { val ((current, next), index) = x val content = current.mkString("-") val isend = next.cata(_.headOption === Some("start"), true) Packet(index + 1, isend, content) } 既存部品とアプリケーションロ ジックを組合せてパイプライン を構築 以下のロジックを実現 - 3つで⼀一つのパケットにする - パケットにシーケンス番号をつける - “start”データの前のパケットにエン ドマークをつける
  26. 26. ⼤大規模データ処理理 val source = io.linesR("data.txt") val pipeline = buildTextToPacket(source).to(sink) pipeline.run.run Packet(1,false,1-2-3) Packet(2,true,4-5-6) Packet(3,true,start-8-9) 1 2 3 4 5 6 start 8 9 汎⽤用部品を⼤大規模データ処理理に 適⽤用 リソース管理 フロー制御 chunk zipWith Next zipWith Index toPacketChannel Sink Process Monad
  27. 27. EventProcessor val queue = EventProcessor.q val source = Vector("1", "2", "3", "4", "5", "6", "start", "8", "9") source foreach { x => queue.enqueueOne(x).run Thread.sleep(2000) } object EventProcessor { val q = async.unboundedQueue[String] val eventStream: Process[Task, String] = q.dequeue } 参考: [scalaz-stream] ストリーミングで状態機械 http://modegramming.blogspot.jp/2015/04/scalaz-stream.html
  28. 28. ストリーム処理理 val source = EventProcessor.eventStream val pipeline = buildTextToPacket(source).to(sink) pipeline.run.run Packet(1,false,1-2-3) Packet(2,true,4-5-6) 汎⽤用ロジックをストリーミング 処理理に適⽤用 リソース管理 フロー制御 chunk zipWith Next zipWith Index toPacketChannel Sink Process Monad
  29. 29. まとめ •  Reactiveには関数型プログラミング •  Responsive, Elastice, Resilience, Message-Driven •  Cuncurrent, Parallel, Distributed •  純粋関数型と普通の関数型/⼿手続き型のトレードオフ •  書やすさ/品質/部品化/将来技術との連続性  vs 性能 •  可能であれば純粋関数型が望ましい •  scalaz stream •  純粋関数型の範囲で相当のことができる •  出きない/苦⼿手なことがあるので応⽤用との相性を⾒見見極める •  Push •  マシンをまたいだストリームの構築
  30. 30. END

×