関数プログラミング(functional programming)は、命令を並べて順次実行させるプログラミングとは異なり、関数の組み合わせと適用によるプログラミングです。関数くらい他のプログラミングでも使うと思われるかもしれませんが、関数プログラミングにおける関数はそれらとは少し違うものです。
関数プログラミング、そして、そのための言語である関数型言語では、安全で生産性が高いと言われることがあります。その理由は、プログラムを構成する部品に要求される性質を、関数プログラミングにおける関数が(言語によっては強制的に)満たしているためです。
良い部品であること
通常、プログラムはより小さな部品を組み合わせ、より大きな部品として構成されます。ここで部品に求められることは、以下のような点になります。
- 他の部品と容易に組み合わせられる
- 同じような他の部品に組み合わせを変更できる
- 組み合わせた他の部品と干渉しない
組み合わせ自体が難しいとしたら、そもそも部品にしておきたいとは思わないでしょうし、また、そうする意味もありません。
ピンポイントで部品を交換することで、プログラムの働きを最小の手間で変更可能となり、すなわち機能の追加や変更が容易となります。
他の部品と干渉してしまう場合、そもそも組み合わせられないか、もしくは組み合わせた時に望む動作をしてくれないことがあります。干渉しない部品から干渉する部品へ交換してしまうことで、原因の把握し難い不具合を起こすこともあるでしょう。
部品としての関数
関数プログラミングにおける関数は、他(命令型プログラミング等)のプログラミングが意味する関数とは少し異なっており、与えた引数のみから結果が決まるといった、強い制約を持ったものとなっています。たとえば、グローバル変数のようなもので結果を変えることは制限されています。一般的なプログラミングの話で出てくる関数よりも、まさに数学の話で出てくる関数をイメージしてもらうのが良いでしょう。
関数が持つこの制約は、前述した部品に求められる要素を満たしてくれています。
関数は、他の関数と並べたり(関数合成)、他の関数の引数になる(高階関数)ことで、部品として組み合わせることができます。たとえば、以下の関数型言語Haskell(https://www.haskell.org/
)のコードは、リストの中身全てに対し関数g
と関数f
をこの順で適用する関数mapFG
を定義しています。関数を引数に持つ高階関数であるmap
を、f
とg
を関数合成した関数に適用したものとして定義しており、実に容易な組み合わせによって処理を記述できます。
mapFG = map (f . g)
引数のみから結果が決まるため、引数が同じであれば毎回必ず同じ結果が得られます。つまり、関数同士お互いの結果に干渉できる経路もありません。
関数プログラミングを学ぶということ
関数の持つ制約は、プログラミングの点では一見窮屈なものに見えます。しかし、この制約は安全なプログラミングのために必要なものです。部品を組み合わせるというプログラミングにおいて最も基本的な操作に対して、我々プログラマから不安を取り除いてくれるのです。逆に制約がない場合、我々が何らかの形の自制により行っているか、危険であることに今は気付いていないかのどちらかでしょう。
無秩序の中では、身の安全を保障するのは自分自身ですが、他に我々プログラマが注力すべきことはたくさんあります。課せられた一定の秩序の中では、機械的に守ることのできる安全もまた存在し、我々はより重要で本質的なことに貴重な時間を使うことができるようになります。
関数プログラミングを学ぶということは、課せられた制約を理解し、そのメリットを享受しつつ、適切に立ち回る方法を学ぶということです。各種制約に縛られるのではなく、逆に自由に使いこなし、安全安心な世界を実現していきましょう。