2015年9月20日日曜日

Scala.jsでJSONをパースする方法

Scala.jsでJSONをパースする方法
やりたいこと
Scala.jsでJSONをScalaのトレイトに変換したい。
変換前のJSON
            
 {
   "firstName": "James",
   "lastName": "Maxwell"
 }
          
変換後のトレイト
            
 trait Person {
   val firstName: String
   val lastName: String
 }
          
変換後のトレイトを定義する
次の手順で前出のトレイトをJavascriptと結びつける。
  1. @js.nativeアノテーションを付ける
  2. js.Objectを継承する
  3. 各メンバにjs.nativeに割り当てる

     @js.native
     trait Person extends js.Object {
       val firstName: String = js.native
       val lastName: String = js.native
     }
          
パースしキャストする
  1. JSON.parseを使ってパースする
  2. パース結果をParson型にキャストする

     val json = """
       {
         "firstName": "James",
         "lastName": "Maxwell"
       }
     """
     
     val obj = JSON.parse( json )
     
     val person = obj.asInstanceOf[Person]
     
     println(s"Hello, ${person.firstName} ${person.lastName}")
          
実行結果
            
          $> Hello, James Maxwell
        

2015年9月4日金曜日

Play2のbroadcastとunicast


Play2の公式サイトのWebSocketの解説を読んでいるとConcurrent.broadcastConcurrent.unicastが出てきますよね。あまり詳しく書かれてなくて、良くわかんないので、ちょっとだけ自分でイジってみました。

その前にまずは、IterateeEnumeratorを簡単に復讐しておきます。Iterateeとは、何かしらの入力が与えられたときに行う処理を保持しているものでした。例えば、入力を足し上げていく処理は、次のように書けます。

val iteratee = Iteratee.fold( 0 ) { (sum, x) => sum + x }

そして、Enumeratorは、Iterateeに入力を与えるものでした。例えば、1から10までの数字をIterateeに入力するには、次のようにします。

val enum = Enumerator.enumerate( 1 to 10 )
val result: Future[Int] = enum.run( iteratee )

結果は、Futureとして取得されます。

result.onComplete( println ) // 55が出力される

以上がIterateeEnumratorです。

では、broadcastunicastは、IterateeEnumratorとどう関係しているのでしょうか?broadcastunicastがやりたいことってのは、基本的には同じです。すなわち、Channelを介してEnumeratorに入力を与えることです。つまり、ChannelEnumerateeに入力を与え、Enumerateeは、Iterateeに入力を与えるという関係になっているんです。

では、実際にbroadcastを使ってみましょう。次の例では、1から4までの数字をChannelを介してEnumeratorに与えている処理を書いてみました。

10 
11 
12 
13 
14 
15 
16 
// Enumeratorとchannelを生成
val (enum, channel) = Concurrent.broadcast[Int]

// Iteratorを実行
val result = enum.run( Iteratee.fold[Int, Int](0) { (sum, x) => sum + x })

// Enumeratorに入力を与える
channel.push( Input.El(1) )
channel.push( Input.El(2) )
channel.push( Input.El(3) )
channel.push( Input.El(4) )
// 入力終わり
channel.end

// 10が出力される
println( Await.result( result, 5.second ) )

上記のコードを見てもらえばわかるように、broadcastを使えば、channel.pushEnumeratorに後から入力を追加することができるんです。これが、broadcastunicastに共通している特徴だと思います。

次に、unicastで同じことしてみましょう。

10 
11 
12 
13 
14 
15 
16 
17 
// Enumeratorとchannelを生成
val enum = Concurrent.unicast[Int] { channel => 

// Enumeratorに入力を与える
channel.push( Input.El(1) )
channel.push( Input.El(2) )
channel.push( Input.El(3) )
channel.push( Input.El(4) )
channel.end

}

// Iteratorを実行
val result = enum.run( Iteratee.fold[Int, Int](0) { (sum, x) => sum + x })

// 10が出力される
println( Await.result( result, 5.second ) )

broadcastとの違いは、unicastは、Enumeratorを返すけど、Channelは返さない点です。Channelを、みんなが使えないようにしているんですね。使えるスコープを限定してChannelを共有できないようにしています。これが違いです。おそらく名前の違いも、このことが由来なんではないでしょうか?

以上、broadcastunicastの違いでした。

Play2のIterateeをイジってみた


Iterateeって何だ!?ってことで頭の悪い僕は、説明読んだだけではわからないので、実際にイジってみることにしました。

とりあえず、公式ページを読んでみて、なんとなく何をするものなのかは掴めた気がします。つまりIterateeってのは、とある入力があったとして、その入力を受け取って、その入力に対して行う処理を持っている箱のようなものなんだなってことです。入力がある度に、そのIterateeが使われるということのようです。例えば、数字を定期的に受け取って、これを足していくとか。いろいろな処理を部品化して、それぞれ組み合わせて使うことができますよっていう、きっと便利なものなんでしょう。

そしてさらに、お話はIterateeだけで終わらずに、Enumeratorってものもあります。これは、Iterateeに入力を与えるものらしいです。これもまた、いろいろ組み合わせていろんな与え方ができるようです。例えば、1から10までの数字を1秒置きにIterateeに渡すとか。

ということは、だいたいはIterateeEnumeratorはペアで使うんですね。

ま、百聞は一見にしかずということで、実際にイジってみましょう。

入力を表示するだけのIteratee

まず、入力をコンソールに表示するだけのIterateeを作ってみましょう。

Iterateeは、トレイトになっていてfoldメソッドが抽象メソッドなので、これを実装すればインスタンスを作れそうです。

def fold[B]( folder: Step[E, A] => Future[B] )( implicit ec: ExecutionContext ): Future[B]

foldメソッドは、引数にfolderという関数を受け取ってますね。このfolderという関数は、Iterateeに入力を与えてくれるもので、folderに「入力を受け取った時の処理(関数)」を渡すというルールになっているようです。つまり、foldメソッド内で、「入力を受け取った時に処理する関数」を作って、それをfolderに渡す処理を書けばOKってことかな。そして、関数を受け取ったfolderは、その関数に入力を渡すようです。ちなみに、implicit ec: ExecutionContextは、Futureに関する処理を行うときにしばしば必要なもので、簡単にいうとスレッドプールです。Futureが使うスレッドをExecutionContextが決めます。Iterateeの本質とは関係ないので、おまじないみたいなものだと思ってください。とりあえず、ここまでの内容を書き下すと次のような感じなります。

// Iterateeが行う処理をfold関数に定義する。
def fold( folder: .. ) = {
  def func = <入力を受け取り、それを処理する関数>
  folder( func )
}

上記のコードのfuncを実装すればよいってことになります。funcの引数は入力です。これはInput.Elという型です。では、戻り値は何でしょう。folderの型を調べてみると、Iterateeになってますね。入力を処理した結果を返すんじゃねーのか!?そうなんです、処理結果を返すんじゃなくて、Iterateeなんです。つまり、次の処理を返しているんですね。次に入力があった時にする処理をIterateeに詰め込んで返すんです。そのIterateeは、また次のIterateeを返し、そのまた次も....というように次から次へ処理していけるようになってるんですね。

ということで、ひたすらコンソール出力を繰り返すIterateeを作ってみましょう。
ここで作るIterateeは、Int型のデータを入力として受け取って、Int型のデータを生成するMyIterateeという名前のIterateeです。

10 
11 
12 
13 
14 
15 
16 
// 入力をコンソール出力するだけのIterateeを定義
class MyIteratee extends Iteratee[Int, Int] {
  def fold[B]( folder: Step[Int, Int] => Future[B] )( implicit ec: ExecutionContext ): Future[B] = {
    // funcの実装
    // 入力を受け取り、次のIterateeを返す
    def func( input: Input[Int] ): Iteratee[Int, Int] = input match {
      case Input.El( e ) => 
        println( e )
        new MyIteratee
      // とりあえず、他の入力は無視する
      case _ => ???
    }
    // funcをStep.Contに包んで渡す
    folder(Step.Cont(func _))
  }
}

funcが、MyIterateeを返すことで、何回もprintlnが実行されるようにしています。folderfuncを渡すとき、funcStep.Contで包んでます。これは、funcは、次の処理をするIterateeを返しますよってことをfolderに教えているんです。この他にもStep.DoneStep.Errorがあります。funcが次の処理を返さない時は、Step.Doneで包みます。

Iterateeができたので、このIterateeに入力を与えて実行してみましょう。Iterateeに入力を与えるのは、folderという関数でした。このfolderという関数を定義して、foldに渡してあげればいいんですね。folderは、Iterateeが生成した処理(MyIterateeでいうところのfunc)に入力を渡します。

10 
11 
12 
13 
14 
15 
// folder関数の定義。
// folder関数は、Iterateeに入力を与える役割を担う。
// 引数のstepは、Iterateeから受け取る。MyIterateeでは、Step.Contを渡している。
def folder( step: Step[Int, Int] ): Future[String] = step match {
  // Step.Contからfuncを取り出す。
  // funcというのは、MyIterateeで定義した入力を受け取って処理する関数。
  case Step.Cont( func ) =>
    // funcに入力(Input.El(1))を渡す
    // funcは新たなMyItrateeを返すが、ここでは無視する。
    val next = func( Input.El(1) )
    // "done"という文字列を返して終了
    Future("done")
  // とりあえず他のStepは無視する
  case _ => ???
}

folderは、Stepを受け取ります。MyIterateeでは、folderStepのサブクラスであるStep.Contを渡してますから、パターンマッチングでStep.Contとして受け取ります。Step.Contは、funcを持っているので、funcを取り出します。このfuncというのは、MyIterateeで定義していて、入力を受け取って、その入力を処理する内容を記述したものでした。したがって、funcは、入力を受け取るので、ここでは、1(Input.El(1))を渡します。1を受け取ったfuncは、それをコンソールに出力し、MyIterateeを返します。funcが返したMyIterateeは、次に入力があった時に実行する処理を格納していますが、ここでは、簡単のために1回しか入力を行わないことにしますので、folder関数内では、MyIterateeを受け取りません。そして、folderの戻り値であるFutureを返します。

では、MyIterateeを実行してみましょう。

// MyIterateeを実行する。
val result = (new MyIteratee).fold( folder )
// '1'と'done'が出力される
println( Await.result(result, 5.second) )

Iterateeを実行するには、foldメソッドを適用します。
結果として、MyIteratee1をコンソール出力し、folderの戻り値の"done"をコンソール出力しています。
ちなみに、Awaitは、Futureが完了するまで、現スレッドで待機するというものです。Thread#joinみたいなもんです。

1から10までの和を計算してみる

ここまでで、Iterateeを定義してから実行するまでの流れはだいたい掴めた気がします。では、次はもうちょっと複雑なことをやってみたいと思います。前のIterateeは、単に入力をコンソールに出力するだけの簡単なものでした。しかも、1回だけ。今回は、1から10までの和を計算するIterateeを作ってみたいと思います。前回より複雑になるところは、10回だけIterateeを繰り返し終了するというところと、1つのIterateeの結果を次のIterateeに渡すというところでしょう。まず、「計算を終了させる」ということを考えてみましょう。前回の例では、fold関数内でStep.Contfolder関数に渡していました。この意味は、「このIterateeは、処理した後も続きを処理するIterateeを返しますよ」っていうことをfolderに伝える役割を果たしていました。folderは、そのことによって続きのIterateeを受け取り、次の入力を渡せるのでした。このようにIterateeStep.Contfolderに渡し続けることで、繰り返し処理ができるのでした。では、その処理を終了するにはどうするのでしょう。前述したようにStepには、Step.Cont以外にもStep.Doneというのがあります。これは、文字通り「このIterateeは、次を返しません。これで終わりです。そしてこれが結果です。」っていうことをfolderに伝えます。Step.Doneを受け取ったfolderは、Step.Doneが持っている結果を取り出し、それを返します。ということは、計算終了時にfolderStep.Doneを渡すIterateeを作れば大丈夫そうです。さっそく、このようなIterateeを定義してみましょう。

// folderにStep.Doneを渡すIterateeの定義。
// Step.Doneは計算結果が必要なので、コンストラクタで計算結果を受け取る。
class DoneIteratee( sum: Int, input: Input[Int] ) extends Iteratee[Int, Int] {
  def fold[B]( folder: Step[Int, Int] => Future[B] )( implicit ec: ExecutionContext ): Future[B] = {
    folder(Step.Done(sum, input))
  }
}

このDoneIterateeの定義自体は簡単ですね。Step.Donefolderに渡しているだけです。ただ、結果を受け渡しできるように、コンストラクタで結果を受け取るようにしています。これで、繰り返し処理を終了することができるようになりました。

次に、MyIterateeを、足し算して結果を次のIterateeに渡して、そのIterateeが前の結果に入力を足し算して、、、というように次々と足し算できるように改良してみましょう。

10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
// 入力の和を計算するIteratee。
// 前のIterateeの結果をコンストラクタで受け取る。
class MyIteratee( sum: Int ) extends Iteratee[Int, Int] {
  def fold[B]( folder: Step[Int, Int] => Future[B] )( implicit ec: ExecutionContext ): Future[B] = {
    // funcの実装
    def func( input: Input[Int] ): Iteratee[Int, Int] = input match {
      case Input.El( e ) =>
        // 入力が10以下の場合は、前の結果と入力を足して、
        // 次のIterateeに渡す
        if( e <= 10 ) new MyIteratee( sum + e )
        // 入力が10を超えた場合は、終了する。
        // DoneIterateeがStep.Doneをfolderに渡す。
        else new DoneIteratee( sum, input )
      case _ => ???
    }
    // funcをStep.Contに包んで渡す
    folder(Step.Cont(func _))
  }
}

前回のMyIterateeからの変更点は、コンストラクタで初期値(=1つ前に実行したIterateeの計算結果)を受け取るようにしたことです。
 class MyIteratee( sum: Int ) 
この初期値にMyIterateefoldで処理した結果を足して、次のMyIterateeに渡します。もうひとつの変更点は、入力を受け取った後の計算処理です。このItrateeの目的は、1から10までの和を計算することなので、入力を受け付けるのは10までにして、それ以外はDoneIterateeを返すようにしました。
if( e <= 10 ) new MyIteratee( sum + e )
else new DoneIteratee( sum, input )
これで入力を足しあげるMyIterateeの完成です。

次に、MyIterateeに入力を渡すfolderを実装します。前回のfolderは、MyIterateeに1度しか入力を渡してなかったので、今回は入力値を増加させながら再帰的に入力を渡すように変更します。また、MyIterateeからStep.Done受け取るようになったので、その場合の処理も追加しました。

10 
def folder( n: Int )( step: Step[Int, Int] ): Future[Int] = step match {
  case Step.Cont( func ) =>
    // Iterateeに入力を渡して、次に実行するIterateeを受け取る。
    val next = func( Input.El( n ) )
    // 入力を1つ増加して、次のIterateeを実行する。
    next.fold( folder( n + 1 ) )
  // Doneを受け取ったら、入力をやめて結果を返す。
  case Step.Done( sum, _ ) => Future( sum )
  case _ => ???
}

それでは、このMyIterateeを実行してみましょう。

val result = (new MyIteratee(0)).fold( folder(1) )
// 55が出力される
println( Await.result(result, 5.second) ) 

「55」と出力されたので、うまく動いているようですね。

さて次は、これを少し改良してみましょう。和を計算するのは変わらないんですが、Iteratee側からStep.Doneを返して終了するのはやめて、入力が終了するまで計算を続けるという仕組みに変更したいと思います。というのも、入力の終了を検知して、何かを処理する方法も知っておきたいからです。MyIteratee側で変更する点は、入力Inputのパターンマッチの部分の分岐を増やすことです。前回では、Input.Elしか判別していませんでしたが、今回はInput.EOFも判別するようにします。

10 
11 
12 
// Input.EOFを受け取るまで計算を続けるように変更
class MyIteratee( sum: Int ) extends Iteratee[Int, Int] {
  def fold[B]( folder: Step[Int, Int] => Future[B] )( implicit ec: ExecutionContext ): Future[B] = {
    def func( input: Input[Int] ): Iteratee[Int, Int] = input match {
      case Input.El( e ) => new MyIteratee( sum + e )
      // この部分を追加
      case Input.EOF => new DoneIteratee( sum, Input.EOF )
      case _ => ???
    }
    folder(Step.Cont(func _))
  }
}

次にfolderの実装です。変更点は入力が10を超えたらInput.EOFIterateeに渡すことだけです。

def folder( n: Int )( step: Step[Int, Int] ): Future[Int] = step match {
  case Step.Cont( func ) =>
    // 入力が10を超えたらInput.EOFを返すように変更
    val input = if( n <= 10 ) Input.El( n ) else Input.EOF
    val next = func( input )
    next.fold( folder( n + 1 ) )
  case Step.Done( sum, _ ) => Future( sum )
  case _ => ???
}

そして実行!

val result = (new MyIteratee(0)).fold( folder(1) )
// 55が出力される
println( Await.result(result, 5.second) ) 

「55」が出力されました。OKです!

もうちょっと汎用的に!?

さあ、次はどうしましょう?MyIterateefolderをもうちょっと汎用的に使えるように改良したいですね。特にfolderは、1から10までの入力しか生成できないですからね。使い道があまりないですね。MyIterateeは、和を取るだけじゃなくて、他の計算もできるように変更します。つまり、足し算をしている部分を何かを計算する関数に置き換えます。
sum + e => f(sum, e)
この関数fは、コンストラクタで渡すようにしましょう。
class MyIteratee( sum: Int, f: (Int, Int) => Int )
ついでに、型もパラメータ化しちゃいましょう。
Int => A変更後のMyIterateeは、次のようになります。

10 
11 
12 
// 何かの処理する関数をコンストラクタに渡す。
class MyIteratee[A]( sum: A, f: (A, A) => A ) extends Iteratee[A, A] {
  def fold[B]( folder: Step[A, A] => Future[B] )( implicit ec: ExecutionContext ): Future[B] = {
    def func( input: Input[A] ): Iteratee[A, A] = input match {
      // sum + e を f(sum, e)に変更
      case Input.El( e ) => new MyIteratee( f(sum, e), f )
      case Input.EOF => new DoneIteratee( sum, Input.EOF )
      case _ => ???
    }
    folder(Step.Cont(func _))
  }
}

では、folderはどうのように汎用的にしましょう? 今までは、1から10までの数字しか入力できませんでしたが、様々な型の羅列を入力として扱えたら、少しは汎用的になるんじゃないでしょうか?とういことで、ある型のリストを渡すと、そのリストの先頭の要素から順次Iterateeに渡すことができるfolder関数を作ってみましょう。

10 
11 
12 
13 
14 
// 型Aのシーケンスを渡す。
def folder[A]( xs: Seq[A] )( step: Step[A, A] ): Future[A] = step match {
  case Step.Cont( func ) =>
    // シーケンスの先頭と残りの要素を抽出する
    val (input, tail) =
      if( xs.nonEmpty ) (Input.El( xs.head ), xs.tail)
      else (Input.EOF, Nil)
    // 先頭の要素をIterateeに渡す
    val next = func( input )
    // 残りの要素を次のIterateeに渡す
    next.fold( folder( tail ) )
  case Step.Done( sum, _ ) => Future( sum )
  case _ => ???
}

では、これらを使って1から10までの和を計算するIterateeを実行してみましょう。

// Iterateeの生成
val iteratee = new MyIteratee[Int](0, (sum, x) => sum + x)
// 1から10までのシーケンスを生成して、Itarateeに渡す
val result = iteratee.fold( folder(1 to 10) )
// 55が出力される
println( Await.result(result, 5.second) )

無事に「55」が出力されました!

さて、いままで長々とIterateeをイジって来ましたが、実はですね、これらのことを行ってくれる便利なヘルパー関数が既に用意されているんですね。まぁ最初からそれを使えば早いんですが、Itrateeを使うためのお勉強ということでご勘弁を。では、それらを使って、1から10までの和を計算する処理を書いてみると次のようになります。

// 和を計算するIterateeの生成
val iteratee = Iteratee.fold[Int, Int](0) { (sum, x) => sum + x }
// 1から10までを順次入力するEnumerator(folder関数のようなものを生成)
val enum = Enumerator.enumerate(1 to 10)
// 実行
val result = enum.run( iteratee )
// 55が出力される
println( Await.result(result, 5.second) )

ここで、Enumeratorというのが登場していますが、これはfolder関数の役割とほぼ同じことをしてくれます。そして、EnumeratorrunメソッドがIterateeを実行してくれます。

まとめ

やっぱり、文章読むだけじゃなくて、実際に自分でイジって動かしてみないと掴めないものってありますよね。ここでやったことだけでは不十分だと思いますが、ItrateeEnumeratorが何をどうやっているのか、だいたい分かったような気がします。
ただ、実際には、IterateeEnumeratorを自力で実装する必要はなく、便利なヘルパーさんがいっぱいいるので、それらを有効活用しましょう!