2012年5月1日火曜日

Scalaへのアプローチ

4月29日(日)にニコニコ超会議 2012超エンジニアミーティングのScalaユーザーグループのコマで「Scalaでプログラムを作りました」のタイトルでお話をさせていただきました。

当日使用したスライドは以下のものです。

セッションの目的は、JavaなどのOOPをやっていて、Scalaをこれから始めたい人向けの情報提供です。

大きく以下の情報を提供しています。

  • Scalaの使い所
  • Scalaプログラミングの魅力

ボク自身は最近はScalazでの型クラスベースのMonadicプログラミングに凝っているので、Scalaプログラミングの面白さというと、このあたりの紹介をしてみたくなるわけですが、これから関数型プログラミングを始める人には、かなりハードルが高い内容でセッションの趣旨と合いません。

これから始める人にとって、普通のOOP、つまりBetter Javaとして使う場合でも有効なScalaを使うメリットは何かというと:

  • DSL
  • 並行プログラミング

の2点だと思います。また並行プログラミングの旬はもう少し先になりそうですし、ボク自身もまだメリットを享受しているとはとてもいえない状態なので、DSLを中心とした話にしてみました。

実際のところ、これから始める人も現在活用している人もDSLがScalaの最大のメリットだと思うので、仮に汎用的な入門記事を書く場合でも、今回の内容を軸に他の要素を加える形になると思います。

Scalaへのアプローチ


これから始める人向けの情報提供ということで、Scalaへのアプローチを考えてみました。まとめの一つ前のスライドです。ここは参考にしてもらえそうなところなので、詳しく説明します。

  • 最初はBetter Java
  • map系、fold系のList処理を導入
  • Option、Eitherの導入
  • flatMap系の演算を導入
  • Scalaz導入

Scalaプログラミングをする層は大きく(1)フレームワークを作ってAPIをDSLで提供する、(2)DSLを使ってアプリケーションを書く、の2つに分けることができます。

(1)と(2)で求められるスキルは大きく異なります。

雑誌の記事やブログなので取り上げられやすいScalaプログラミングの華やかな所は、トレイト、モナド、型クラスといった新技術ですが、これらを駆使したプログラミングは(1)のフレームワーク開発では必須ですが、(2)のアプリケーション開発では、知っていた方がよいのは確かですが、知らなくてもほぼ困りません。

最初はBetter Java

そこで、最初の段階ではBetter Javaに徹して使用し、PlayやScaldingといったDSLを活用するというアプローチがよいのではないかと思います。DSLを使う上でモナドを使う必要があるケースが出てきますが、これは個々のDSLの使い方のイディオムとして丸暗記しておけば十分です。

たとえばScala的にはOptionを使ってnull値の使用は避けるのが普通ですが、この段階ではそういったことは気にせず普通のJavaプログラミングのつもりで望むのがよいでしょう。まずは、普通に使えるようになるのが大事です。

トレイトはOOPをやっている人なら理解するのは容易なので最初の段階から導入しても問題ないでしょう。

Scalaを業務に導入することを考える場合、最初の段階ではBetter Java + トレイトがよい落とし所です。Scalaを導入する最大のメリットは、これから続々と登場することが予想される便利DSL+フレームワークを利用することですが、これが目的と割り切れば、この段階で止めてしまってもよいでしょう。

map系、fold系のList処理を導入

関数型プログラミングはList処理が非常に便利なのが美点なので、次の段階ではこれを使うようにしていきます。

java.util.ArrayListに対応するScalaのオブジェクトは、scala.collection.mutable.ArrayBufferですが、この段階までは、ArrayBufferを中心としたプログラミングになっているはずです。

これを、最終的にはList(scala.collection.immutable.List)を中心としたプログラミングに転換していくのが目標です。

Listの個々の要素に対する変換処理を記述するmapメソッド、List全体の変換処理を記述するfold系メソッド(foldLeftやreduceLeftなど)を組合わせてロジックを記述するのが大事なので、できるだけそういった方向でプログラミングしていくようにします。

Option、Eitherの導入

List処理に慣れたらOptionやEitherを導入します。

nullを回避して頑健なプログラミングをするためにOptionを最初の段階で導入するほうがよいという意見もありますが、Monadicプログラミングができない状態でOptionを使うと、if式やmatch式の羅列による煩雑なプログラミングになってしまい、プログラミングの楽しさという観点ではデメリットが多いので、無理をして導入する必要はないかなと思います。

もちろんOptionの価値を理解した上で積極的に活用したいという人が最初の段階からトライするのは非常によいことです。

Either(あるいはScalazのValidationやLogger)は、エラー処理を関数型的に取り扱うのに必須のオブジェクトなので、OptionとList処理が慣れた段階で導入するとよいと思います。Either導入に伴ってエラー処理も関数型流にしていきます。関数型流のエラー処理は、将来並行プログラミングに移行したときに必須となると予想されるので、今のうちにできるだけ慣れておくとよいでしょう。

flatMap系の演算を導入

最近の関数型プログラミングではモナドを多用します。モナド中心のプログラミングといっても過言はないほどです。

その中心となるのがflatMapメソッドです。次の段階ではflatMapメソッドを使ったMonadicプログラミングをマスターしていきます。

ListやOptionもモナドなので、Monadicプログラミングを使うとより便利に操作できます。OptionもMonadicプログラミングで使っていかないと便利さが実感できないので、このあたりから本格活用していくとよいでしょう。

Scalaz導入

本格的な関数型プログラミング、Monadicプログラミングを行う場合にはScalazを使うのがとても便利です。このブログでもScala+Scalazの枠組み上でScalaプログラミングのイディオムを整理しています。

正直なところScalazはかなり難しいのですが、フレームワークのAPIをDSLで提供する場合には、Scalazを使いこなすスキルが必要になります。

2 件のコメント:

  1. >PlayやScaldingといったDSL
    Play は DSL ではなくフレームワークだと思うのですが、どういう意図があるのでしょうか。

    >フレームワークのAPIをDSLで提供する場合には、Scalazを使いこなすスキルが必要になります。
    これはどのような理由で必要になるのでしょうか。

    返信削除
  2. PlayのScala向けフレームワークのAPIを、DSL的に見るかどうかは主観によると思いますので、伝統的なAPIと見えるのであればそれでよいと思います。

    フレームワーク開発者は、Scalazを採用するかどうかは別にして、使いこなすスキルは必要になると思いますよ。今風の関数型プログラミングのエッセンスが詰まってるので。このあたりの技術を使わないとDSL作るときの選択肢が狭くなります。

    返信削除