Play2.1のfunctional packageのApplicativeを使う

というわけで、Play2.1から独自のFunctorとかApplicativeとかAlternative(ApplicativePlus)があるので簡単にOptionのApplicativeの使い方だけ紹介。
https://github.com/playframework/Play20/blob/2.1.0/framework/src/play/src/main/scala/play/api/libs/functional/Util.scala
Scalazでその辺り知ってる人は、簡単に理解できるはずです。ところで、なぜかMonadのtypeclassはないんですね・・・。


ちょっと引用
http://qiita.com/items/b25b14284883ee1549e7

 def notification = Action(parse.json){ request =>
    val optText = request.body.\("text").asOpt[String]
    val optId = request.body.\("id").asOpt[String]
    val optUser = request.body.\("user").asOpt[String]

    val tweet = for(text <- optText; id <- optId; user <- optUser) yield new Tweet(text,id,user)
  }

スゴイ!Optionスゴイよ!!(あと、forとかyieldも)


はい、Option便利ですけど、このパターンMonadじゃないのでfor式必要ないですねApplicative(もっと正確にはApply)ですね。つまりこの前書いたこれ

Scalacheck の Arbitrary.scala を scalaz の Applicative を使って書き換えてみる

と(構文がちょっとだけ違うだけで)ほぼ全く同じことが、Scalazを使わずに、Play2.1の中にあるfunctionalのものでできます。以下のようになります

import play.api.libs.functional.syntax._

def notification = Action(parse.json){ request =>
  (request.body.\("text").asOpt[String] ~ 
   request.body.\("id").asOpt[String] ~ 
   request.body.\("user").asOpt[String]
  )(Tweet)
}

わー、変数がいっぱい消えて、さらに短く書けましたね。Scalaz分かる人にむけて簡単に説明しておくと、~というのがApplicativeBuilderの|@|に相当するものです。記号が嫌いな人向けに~ではなくandという別名もあるみたいです。

https://github.com/playframework/Play20/blob/2.1.0/framework/src/play/src/main/scala/play/api/libs/functional/Util.scala#L43

CanBuild1からCanBuild21が、ApplicativeBuilderですかね。*1その他tupledとか、ある程度Scalazと同じメソッドありそうです。

(scalazと比べた場合に)細かいところの使い勝手でツッコミどころは大量にありそうですが、まぁこの程度のOptionのApplicativeは(Scalazの依存を加えずに)手軽に使えるので、使ってみればいいんじゃないでしょうかね。
*2



追記:
今回のやつは、「とりあえず使えるようになってるから試しに使ってみた」という感じですが、「そもそもPlayにおいて、普通にやるならバリデーション使えばよい(?)」とか「functionalはどちらかというと内部実装のためにあるもので、あまりユーザーが直接使うことを意図していないかもしれない(?)」ので(以下のtogetter参照)
Play2.1のfunctionalパッケージとバリデーション
そのあたりは自己責任というか、適切な方法を調べましょう(というか、教えてください(´・ω・`) )

*1:これに関しては、Scalazと違い、半自動生成で大量に用意してある

*2:もっと汎用的にやろうとしたり、徹底的に使おうとすると、typeclassのデフォルトのインスタンスが少なかったりして、Playのデフォルトのものだけでは不便になってくると思いますが