44
関西関数型道場 2014-09-06 高速・軽量Webフレームワーク で学ぶ

Introduction to Spray at Kansai Functional Programming

Embed Size (px)

DESCRIPTION

Introduction to Spray at Kansai Functional Programming

Citation preview

Page 1: Introduction to Spray at Kansai Functional Programming

関西関数型道場 2014-09-06

高速・軽量Webフレームワーク

で学ぶ

Page 2: Introduction to Spray at Kansai Functional Programming

• Suguru Hamazaki (@hamazy)

• とあるマーケティング会社で勤務

• 先週まで WordPress ホスティングの会社にいました

Page 3: Introduction to Spray at Kansai Functional Programming

• an open-source toolkit for building REST/HTTP-based integration layers

• on top of Scala and Akka

• asynchronous, actor-based, fast, lightweight, modular and testable

— from http://spray.io/

REST/HTTPによる統合レイヤーを構築するための、オープンソースなツールキット

Scala と Akka がベース

非同期、Actorベース、高速、軽量、モジュラー化されており、テスト可能

Page 4: Introduction to Spray at Kansai Functional Programming

Akka is a toolkit and runtime for building highly concurrent, distributed,

and fault tolerant event-driven applications on the JVM.

— from http://akka.io/

Akka は並列度が高く、分散した、耐障害性の高い、イベント駆動型のアプリケーションを作成するツールキットであり、実行環境です。

Page 5: Introduction to Spray at Kansai Functional Programming

Actor• 並行計算のモデル

• スレッドモデルよりも抽象度が高く、扱い易い

• イベント駆動型の受信ループでメッセージを非同期に処理

• Non-blocking で高速

• Akkaのactorは非常に軽量

• 1GBのメモリーにつき数百万のactorが動作

Page 6: Introduction to Spray at Kansai Functional Programming

(demo)

Sprayのアプリで、 Actorがどのように使われるか見てみましょう

Page 7: Introduction to Spray at Kansai Functional Programming

• ActorSystem から Actor を作った

• Spray が提供する Actor とメッセージをやりとりして、簡単な HTTP のサービスが出来た

• Http.Bind, Http.Bound, Http.Connected, Http.Register, HttpRequest, HttpResponse

Page 8: Introduction to Spray at Kansai Functional Programming

• HTTPのイベントに対応したロジックはそれはそれでわかりやすい

• が、全部それで書くのはしんどい

• HTTPとアプリ、レイヤーは分けたい

Page 9: Introduction to Spray at Kansai Functional Programming

Spray Routing

Page 10: Introduction to Spray at Kansai Functional Programming

• ルーティングを定義

• どんなリクエストをどこで処理するか

• HTTPからアプリのレイヤーへの橋渡し

• 抽象化された柔軟な内部DSLで書ける

• 内部DSLなのでScalaの型チェックが入る

Page 11: Introduction to Spray at Kansai Functional Programming

(demo)

簡単なルーティングの定義を 見てみましょう

Page 12: Introduction to Spray at Kansai Functional Programming

• リクエストのメソッド名、パス、パラメーターで、処理するリクエストを抽出できた

• パス、パラメーターの構造に応じて、処理の型が決まった

• 型が合わないとコンパイルエラー

Page 13: Introduction to Spray at Kansai Functional Programming

型安全は嬉しい

Page 14: Introduction to Spray at Kansai Functional Programming

柔軟性も欲しい

Page 15: Introduction to Spray at Kansai Functional Programming

complete の例

complete(StatusCodes.OK)

complete(HttpResponse(entity = "Hello"))

complete("Hello.") String 型StatusCode 型

HttpResponse 型⋮

Page 16: Introduction to Spray at Kansai Functional Programming

もっと色々渡したい

• JSON オブジェクト

• XML (NodeSeq型)

• Future型

• 任意の型のドメインオブジェクト

Page 17: Introduction to Spray at Kansai Functional Programming

渡す値の型が共通のインターフェイスを 継承することは、とても期待できない

Page 18: Introduction to Spray at Kansai Functional Programming

さてどうしましょう

Page 19: Introduction to Spray at Kansai Functional Programming

メソッドオーバーローディング?

いいえ、implicit です

Page 20: Introduction to Spray at Kansai Functional Programming

• 似たコードの繰り返しを防ぐ

• 型消去にまつわる問題を回避

• Future[String] と Future[NodeSeq] を区別してもらわないと困る

Page 21: Introduction to Spray at Kansai Functional Programming

実際の complete の定義

def complete: (⇒ ToResponseMarshallable) ⇒ StandardRoute

Page 22: Introduction to Spray at Kansai Functional Programming

ほぼこれに一致

def complete( marshallable: ⇒ ToResponseMarshallable): StandardRoute

(このメソッドを関数へ持ち上げると、先ほどのコードになる)

Page 23: Introduction to Spray at Kansai Functional Programming

この関数で、 どうやって多様な型に対応しているのか?

def complete( marshallable: ⇒ ToResponseMarshallable): StandardRoute

Page 24: Introduction to Spray at Kansai Functional Programming

Implicits

Page 25: Introduction to Spray at Kansai Functional Programming

Implicits

• 暗黙の型変換 / 暗黙のパラメーター

• Haskell でいう型クラスを Scala で実現するためのもの

Page 26: Introduction to Spray at Kansai Functional Programming

Haskell の型クラス

class Ord a where (<=) :: a -> a -> Bool

instance (Ord a, Ord b) => Ord (a, b) where (xa, xb) <= (ya, yb) = xa < xb || (xa == ya && xb <= yb)

順序という概念を定義

概念をペアについて実装したモデル

Page 27: Introduction to Spray at Kansai Functional Programming

sort :: Ord a => [a] -> [a]

> sort [ (3, 5), (2, 4), (3, 4) ]

概念を前提とする関数を定義

関数をこのように使用できるのは、 ペアについて実装したモデルがあるため

Page 28: Introduction to Spray at Kansai Functional Programming

Scala の暗黙パラメーターでtrait Ord[T] { def compare (a:T, b:T):Boolean}

implicit object intOrd extends Ord[Int] { def compare (a:Int, b:Int):Boolean = a <= b}

順序という概念を定義

概念を Int について実装したモデル

Page 29: Introduction to Spray at Kansai Functional Programming

def sort[T](xs:List[T])(implicit ordT:Ord[T]):List[T]

> sort (List (3, 2, 1))List (1, 2, 3)

概念を前提とする関数を定義

関数をこのように使用できるのは、 ペアについて実装したモデルがあるため

Page 30: Introduction to Spray at Kansai Functional Programming

更に、暗黙型変換でtrait Ordered[T] { def compare (o: T) : Boolean}

implicit def mkOrd[T](x:T)(implicit ev: Ord[T]): Ordered[T] = new Ordered[T] { def compare(o: T) = ev.compare(x, o) }

> 1.compare(2)true

OOP的に書けるようになった!

Page 31: Introduction to Spray at Kansai Functional Programming

implicit のルール

• プレフィックスなしでアクセスできる、implicit な値 (もしくは変換) を探しにいく

• 目的の型 (変換の場合は変換元と変換先) のコンパニオンオブジェクトのメンバーから、implicit な値 (もしくは変換) を探しにいく

詳しくは、 http://docs.scala-lang.org/tutorials/FAQ/finding-implicits.html 参照

Page 32: Introduction to Spray at Kansai Functional Programming

complete を もう一度見てみる

Page 33: Introduction to Spray at Kansai Functional Programming

trait RouteDirectives {… def complete: (⇒ ToResponseMarshallable): StandardRoute…}

complete("Hello.") メソッド定義

メソッド呼び出し

ToResponseMarshallable という概念を String で実現したモデルが、どこ

かにあるはず

Page 34: Introduction to Spray at Kansai Functional Programming

object ToResponseMarshallable { implicit def isMarshallable[T](value: T)(implicit marshaller: ToResponseMarshaller[T]): ToResponseMarshallable…}

ToResponseMarshaller という概念を String で実現したモデルが、どこかにあるはず

Page 35: Introduction to Spray at Kansai Functional Programming

object ToResponseMarshaller extends BasicToResponseMarshallers with MetaToResponseMarshallers with LowPriorityToResponseMarshallerImplicits { def fromMarshaller[T] (status: StatusCode = StatusCodes.OK, headers: Seq[HttpHeader] = Nil) (implicit m: Marshaller[T]): ToResponseMarshaller[T]…}

Marshaller という概念を String で実現したモデルが、どこかにあるはず

Page 36: Introduction to Spray at Kansai Functional Programming

object Marshaller extends BasicMarshallers with MetaMarshallers with MultipartMarshallers {…}

trait BasicMarshallers {… implicit val StringMarshaller: Marshaller[String]…}

Marshaller という概念を String で実現したモデルが、ここにあった!

Page 37: Introduction to Spray at Kansai Functional Programming

• 結局、Marshaller[String]があれば充分だった

• 他にも様々な Marshaller が Spray に用意されている

• 独自の型で complete を利用する場合は、有効なスコープやその型のコンパニオンオブジェクトに implicit な Marshaller[T] を定義すればよい

Page 38: Introduction to Spray at Kansai Functional Programming

まとめ• AkkaベースのSprayはActorを使って非同期、ノンブロッキングで動いている

• Spray のルーティング定義は型安全かつ柔軟な DSL で書ける

• それには Scala の implicit の仕組みを利用している

• Scala の implicit は Haskell の型クラスに相当する

Page 39: Introduction to Spray at Kansai Functional Programming

Scala も Haskell もその他の言語も 一緒に勉強しましょう

Page 40: Introduction to Spray at Kansai Functional Programming

今日はお話しできなかった事

• 型安全で柔軟な Spray Routing の DSL には、他に Shapeless が一役買っている

• C++ の Template Meta-Programming のような、コンパイル時における型レベルのプログラミング

Page 41: Introduction to Spray at Kansai Functional Programming

See you soon!

Page 42: Introduction to Spray at Kansai Functional Programming

参考情報

• The Magnet Pattern (from spray blog)

• Type Classes as Objects and Implicits (PDF)

• Spray on Akka (Typesafe webinar on 2013-11-19)

Page 43: Introduction to Spray at Kansai Functional Programming

QA

Page 44: Introduction to Spray at Kansai Functional Programming

Image Credits