関数型プログラミングの上達プロセス

私は関数型プログラミングを初めて半年も経ってないペーペーですが、ペーペーなりに思う事があったので書いてみます。

上達プロセス

関数型プログラミングは大体以下のようなプロセスを経て習熟していくのではないかという気がしています。(Scalaを使うことを想定しています)

  1. ラムダ式を覚える
  2. 標準ライブラリについてくるコレクション操作を行う高階関数を使い始める
  3. 自分で高階関数を定義して使う
  4. 副作用の無いコードを意識して書き始める
  5. レガシーな使い方をする(制御構造として使う)for文やwhlile文、if文をあまり使わなくなる
  6. なんとなくモナドが分かってくる
  7. flatMapを多用し始める、Optionをパターンマッチ以外でも使うようになってくる
  8. え?Scalaのfor文ってもっと積極的に活用するべきじゃね?と気づく
  9. 型クラス(higher-kinded polymorphism)を使ってさらなる抽象化を目指す
  10. ScalazやHaskellの世界に旅立つ(変わった人はF#に行く)

自分は今8と9の真ん中あたりなので、10以降に何が待ち構えているのかはよくわかりません。9と10の間にまだステップがあるような気もします。そして、なんとなく、10以降にあるのは現実的な応用例がそこまで無いというか、覚えてもそこまで便利じゃない、役に立つシーンが中々無い、みたいな領域なんじゃないか…と少し思っています。なので、個人的にはScalazの一部のモナドが使えるようになればそれ以上関数型プログラミングにのめり込む必要は無いかな、という気がしています。推測なので本当にそうかどうかは知りません。ただ、1~8あたりは大体の人が通る道なのではないかという気がしています。

最低限知っててほしい内容

そんで、1~5はプログラマなら全員が知っててほしいな、と思うところです。私の職場で見かけるコードはほとんどが昔ながらのforループやif文で構成されており、読むのもデバッグするのもいじるのもしんどいです。何より個人的に大問題だと思うのがその生産性です。1~5くらいまで出来るようになった人は、以下のようなコードを二度と書きたくない、見たくも無い、関わりたくも無いときっと思っている事でしょう。

[java]

List<Employees> list = repository.getAllEmployees();
List<String> empNamesWithIndex = new List<String>();

for(int i = 0; i < list.size() ; i++){
if(list.get(i).divisionCode.equals("A123")){
empNamesWithIndex.add("社員" + i + ": " +list.get(i).name)
}
}

[/java]

repository.getAllEmployees()は定数時間で終わると思ってください(良い例が思いつかなかった)。厳密に同じコードにはならないですが、一通りの事を覚えると上記のコードは下記のように書きます。(Scalaの場合)

[scala]
val empNamesWithIndex = list.filter(_.divCode == "A123").zipWithIndex
.map{case (i, n) => s"社員$i: $n"}
[/scala]

きっと、アドテクとかモバゲーとかの最先端にいるエンジニアには想像もつかないことと思いますが、うちの会社ではいまだにVB6からの移行が~、とか言ってるような連中であふれています。そういう人たちにラムダ式とかモナド使おうぜ!とか言っても、「ウホウホ?」みたいな感じでしょう。特にうちの会社だけがそうなのではなく、そういう会社ってまだたくさんあると思います。

私は同じ職場の全社員に関数型プログラミングを完璧に覚えてほしいと要求するつもりはないですが、少なくともレガシーな制御構造としてのforやif、whileをほとんど書かなくても良いというレベルにまではなってほしいと考えています。なぜならば、上掲のコード程度ならそれほど教育コストを掛けずに覚えれる割に得るものがかなり大きいからです。

Java 8がリリースされたことによって、広く使われているJavaでも関数型プログラミングスタイルでコードを書くことができるようになりました(不足はかなりあるものの)。この期に一気に広まってほしいなあと思う次第です。