プログラマが知るべき97のこと/関数型プログラミングを学ぶことの重要性
最近プログラミングコミュニティでは、再び関数型プログラミングへの関心が高まっています。その理由としては、業界全体でマルチコアヘの移行が進んでいる、ということもあるでしょう。移行によって生じる新たな課題への対処に、関数型パラダイムの持つ特性がうまく合致することが明らかになってきたからです。確かにそれも重要な理由です。しかし、仮にそれだけなら、私がここでわざわざ「あなたも関数型プログラミングを学ぶべき」という文章を書くこともなかったと思います。
関数型プログラミングのパラダイムを十分に学べば、その知識、技術は、マルチコアヘの対応以外にも幅広く役立つでしょう。まず、自分の書くコードの品質を大きく高めることができます。重要なのは、参照透過性(referential transparency)が向上するということです。
参照透過性が高い、というのは非常に素晴らしいことです。参照透過性が高いとは、関数がどこでいつ呼び出されようと、入力が同じであれば、常に得られる結果が同じになる、ということを意味します。つまり、関数の評価結果が状態変化の副作用に左右されることが少ない(あるいは、まったくない)ということです。
手続き型プログラミングに不具合が生じる原因となりやすいのが、「可変(mutable)な変数」です。本書の読者なら、ある変数の値が、状況によって予期したとおりにならず、その理由を調べた経験が少なからずあるでしょう。「可視性セマンティクス(visibility semantics)」などが、そうした目に見えにくい不具合を減らす上で役立つことはありますし、少なくとも、不具合の箇所の絞り込みにかなり役立つのは間違いないでしょう。しかし、ここで本当に問題なのは、そもそも、変数の値が変わってしまうような設計をしてしまったことです。
そういう設計を防ぐために参考になるものは、業界全体を見渡してもあまり見つからないことは確かです。オブジェクト指向言語の入門書などには、変数の値が変わる設計を、暗黙のうちに助長してしまっているものもあります。比較的「長生き」するオブジェクトたちが、互いの値や状態を変えるメソッド(mutator methods)を次々に呼び出す、というようなプログラム例が図解入りで載っていたりするからです。これはとても危険です。
しかし、適切なテスト駆動設計をすれば、特に「オブジェクトではなく、ロールのモックを作成すること[1]」を心がけるようにすれば、不要な可変性は、設計から排除できるでしょう。
大事なことは、可変なメンバー変数の参照が必要になるような設計をしないことです。それよりも、小さな関数を数多く作り、個々の役割を限定する方が得策です。個々の関数は、自らに渡される引数にのみ作用するようにします。そうすれば不具合は減り、おそらくデバッグも簡単になるでしょう。この設計では、仮に変数に不適切な値が入ったとしても、その箇所を特定するのが容易になるからです。そうでない設計では、不適切な代入がどのようなコンテキストで行われたかを推測する、ということまで必要になるおそれがあります。このように参照透過性を高めることは非常に大切なのですが、それを血肉となるくらい深く理解するには、やはり関数型プログラミング言語を学ぶのが一番でしょう。関数型の言語では、参照透過性の高いプログラムを書くのがごく当たり前のことだからです。
もちろん、参照透過性を高めることがどんな状況でも好ましいというわけではありません。参照透過性を高めるようなスタイルは、オブジェクト指向システムの場合、ユーザインターフェース開発よりも、たとえばドメインモデル開発において(つまり、コラボレーションがビジネスルールの複雑さの低減に役立つような場合に)好結果につながりやすいよう です。
関数型プログラミングのパラダイムについてよく学ぶことで、関数型言語での開発以外の場面にも、学んだことをうまく応用できるようになるでしょう。オブジェクト指向システムであっても、参照透過性を高めることができれば、利益は大きいはずです。一般に信じられているよりも、オブジェクト指向システムと関数型システムの間に違いはありません。中には、「突き詰めれば、関数型プログラミングとオブジェクト指向プログラミングは、どちらもお互いの鏡像にすぎない」などと言う人もいます。「陰と陽」のような関係、と言ってもいいかもしれません。