野狐消暇録

所感を記す

『Javaによる関数プログラミング』を読みました。

Java8になり、ラムダ式がサポートされました。

Stream APIという、関数プログラミングのためのAPIも提供されるようです。

Javaによる関数プログラミング』はそんなリニューアルしたJavaの使い方を解説した本です。

本には、どこでどう関数プログラミングしたら良いかが書いてあり、とても参考になりました。著者はオブジェクト指向のためのデザインパターンを引いて関数プログラミングを説明しており、理解が進みました。

特に関心した点、気付かされた点を以下に挙げます。

これは僕のプログラミングの中に、今までありませんでした。複数の似たメソッドの差分をパラメータ化する場合、値として括り出す事しかできなかったのです。例えば、SQL文字列を引数として渡し、渡したSQLを発行するDBアクセス用のメソッドがあったとします。この時、SQLは確かに処理ですが、型としてはただの文字列=String型であり、差分は飽くまでも、値の形にするしかありませんでした。しかし、ラムダ式SQL文字列と異なり、意味だけでなく、プログラムにとって実際に処理です。これにより、所謂ボイラープレートを括り出したメソッドが作れるかもしれない。これは僕のプログラミングにとって大きな進歩です。これからはコーディングに際し、値だけでなく、処理の差分もパラメータ化できるという事になるのです。

オブジェクト指向関数プログラミングが近い関係にあるという話は以前にも聞いた事がありました。自分の経験としても、最初に関数プログラミング的に設計、コーディングを進めて、機能が完成した後、オブジェクト指向の考えに沿ってリファクタリングするのが、いつものコーディングスタイルでした。

具体的には、最初に入出力を繋ぐような、この本のタイトルにもなっているStreamを作るようなプログラムを書きます。画面遷移が多いプログラムだとこの方法は使えませんが、その場合は、画面遷移を表にまとめる所から始めます。そして、Streamを作る中で、どうしても、状態として管理せざるを得ない部分に注意します。なぜかというと、ひとつには、ここにバグが入りやすいからです。さらに、状態として管理する部分が常にひとつの状態を取っているか、マルチスレッドでアクセスされたりしないかも考えます。そうやって注意しながらコーディングを進め、一応動く所までいったら、簡単なテストの後、プログラムを見直します。ここでオブジェクト指向について考えます。同じような情報をひとつのクラスに纏めます。アクセスレベルも見直し、基本的には小さくします。かなり書き直す事も良くあります。そうしたら一応完成。極端に速度が遅くない事を天に祈ります。これは冗談です。

速度が遅かったら、DBアクセスとか、OSのメモリ使用量が極端に増加していないかとか、色々調査が必要になると思いますが、あまりやった事がありません。今後できるようになるのが、自分の課題です。

話を元に戻すと、そういう、関数プログラミング的なアプローチと、オブジェクト指向で推奨されているアプローチと、両方使ってコーディングしている中で、相性の良さを肌感覚では感じていました。オブジェクト指向に基づいてリファクタリングすると、所謂関数プログラミングの指針で書いたコードも綺麗になる事が良くあったからです。しかし、この本の著者は、そういう実感レベルから更に踏み込み、オブジェクト指向のためのデザインパターンの用語を用いて、関数プログラミングのアプローチを説明しています。

例えば、ストラテジ・パターンです。ストラテジは日本語に訳すと戦略です。ここで戦略は、プログラムの実行方法を指しています。これは、メソッドに戦略、つまり実行方法を引数として渡す事により、そのメソッドの実行方法を切り替えるというデザインです。関数プログラミングに当て嵌めると、戦略がラムダ式であり、冒頭に挙げた処理を引数として渡すメソッドは、ストラテジ・パターンとして説明できます。

また、ラムダ式の実装がJavaの文法の中でどのように実現されているかの解説も興味深く読みました。自分は、まだちゃんと理解できていないように思いますが、Javaの継承の仕組みを利用してラムダ式を実現しているようです。そうした点、関数プログラミングオブジェクト指向の関係について、もっと理解したいと感じました。

  • 引数に取ったオブジェクトではなく、新しいオブジェクトを作って返却する。

これも知ってはいたのですが、この事により、変数の不変性が保たれる訳です。引数に渡したオブジェクトがコレクションであったとして、単にコレクションへの参照が更新されないという事ではなく、コレクションの要素が更新されない。こういう使い方をする事により、中身まで不変な変数という事になる。これはちょっとなるほどと思いました。そうやって、次々に新しいコレクションを生成しながら、処理を進めるという事です。この考え方もそうですが、関数プログラミングの手法は、所謂関数型言語でなくても使える手法がほとんどで、大変学び甲斐があります。この間書いたExcelVBAプログラムでコレクションを扱う機会があり、早速この方法を使いました。VBAプログラミング言語としては簡素なもので、その時使っていたコレクションは単なる二次元配列でした。この二次元配列を引数にとり、2つの列の値をマージした新しい列を作成し、その列を返すようにしました。この事により、元の二次元配列は破壊されずに、新しいコレクションが手に入ったわけです。VBA関数プログラミングを支援する仕組みはほとんどないように思いますが、この程度の事は普通のプログラミング言語がサポートしている範囲の機能で充分可能です。

 

ここに挙げた以外にも、面白い話題はいくつもあり、とても良い本に出会ったと思います。この本は既に関数プログラミングに慣れたプログラマには優しすぎるかもしれませんが、僕にはちょうど良いようです。また読み返したいと思います。