kbits

なぜ関数型プログラミングは重要か

原題: Why Functional Programming Matters
著者: John Hughes (The University, Glasgow)
公開日: 1990年(初出は The Computer Journal, 32(2):98-107, 1989年4月)
ソースURL: Why Functional Programming Matters
アーカイブ日: 2026-06-11


要約

この論文は、関数型プログラミングの本当の価値はどこにあるのかを問い直す古典的論考である。著者の John Hughes は、関数型言語の利点としてしばしば挙げられる「代入文がない」「副作用がない」「参照透過性がある」といった性質は、いずれも何ができるかではなく何ができないかを述べているにすぎないと指摘する。彼はこれを、快楽を否定すれば美徳が得られると信じる中世の修道士になぞらえて痛烈に批判する。こうした消極的なメリットでは、なぜ関数型プログラムが手続き型に比べて一桁短く書けるのかを説明できないし、関数型プログラマーに対して「ではどう書くべきか」という積極的な指針も与えられない。

構造化プログラミングとの類推

Hughes は構造化プログラミングとの類推から本質に迫る。構造化プログラミングの利点もまた、当初は「goto を使わない」「ブロックに複数の入口や出口を持たせない」といった否定文の集まりとして語られた。しかしその真の貢献は、プログラムを意味のある部品へと分割するモジュール設計にあった。同じことが関数型プログラミングにも当てはまる。関数型プログラミングの本質は、プログラムを小さな部品へ分解し、それらを結合するための新しい「糊(glue)」を提供することで、モジュール性を飛躍的に高める点にある、というのが論文全体を貫く主張である。

モジュール性こそが成功するプログラミングの鍵である。

部品が小さく単純であればあるほど再利用しやすく、保守も容易になる。しかし部品を小さく分けられるかどうかは、それらを後で組み合わせる手段、すなわち糊の表現力に依存する。Hughes は関数型言語が提供する糊として二種類を挙げる。

第一の糊 — 高階関数

一つ目は高階関数である。関数を引数として受け取ったり、関数を結果として返したりできる能力だ。典型例として foldr が示される。リストの合計を求める sum を定義するとき、再帰の骨格(foldr)と具体的な演算(+)を分離できる。いったん骨格を取り出してしまえば、同じパターンを別の演算に差し替えるだけで product(積)や anytrue(いずれかが真か)などが書ける。木構造に対しても同様に foldtree を定義でき、それを土台に sumtree(木の数値の合計)、labels(ラベルの一覧)、maptree(全ラベルへの関数適用)が簡潔に表現できる。

ここから重要な指針が導かれる。新しいデータ型を定義したら、必ずそれに対する高階関数(fold のような)を併せて書くべきである。そうすればデータ型の操作が容易になり、内部表現の詳細を一箇所に局所化できる。これは事実上、プログラミング言語そのものを拡張するに等しい。

第二の糊 — 遅延評価

二つ目は遅延評価である。これによりプログラム全体を「生成器(generator)」と「選択器(selector)」へと分離できる。f の出力を一時ファイルに溜め込むことなく、g が必要とする分だけ f を逐次的に実行する同期的な実行が可能になる。結果として無限リストを扱えるようになり、ループの本体と終了条件を別々の部品として書けるようになる。

この威力を Hughes は数値計算で示す。平方根を求める Newton-Raphson 法では、初期値 a0 に関数 next を繰り返し適用して近似値の無限リストを生成する repeat、次の近似値を計算する next n x = (x + n/x)/2、許容誤差に収まった最初の値を選ぶ within eps を用意する。これらを sqrt a0 eps n = within eps (repeat (next n) a0) と合成するだけで実装が完成する。従来の一体化したプログラムでは、誤差判定を「差分」から「比率」へ変えるには全体を書き直す必要があるが、このモジュール化された設計では選択器 withinrelative に差し替えるだけで relativesqrt が得られる。

同じ発想は数値微分や数値積分へ拡張される。differentiate が刻み幅 h0 から近似値列を生成し、誤差項を消去する高階関数 improve をその列に適用すれば収束が劇的に改善する。improve を重ねて適用すれば高次精度の手法が数行で得られ、within eps (improve (improve (improve (differentiate h0 f x)))) のように書ける。さらに superimprove を繰り返しつつ毎回最良の近似値を取る)を使えば、用いる数値計算法を動的に切り替える超適応的なアルゴリズムまで数行で表現できる。積分でも improve (integrate f 0 1)(ただし f x = 1/(1 + x*x))が π/4 を高速に求める8次法となり、最初の近似値はわずか5回の関数評価で小数点以下5桁まで正確だという。

AIへの応用 — α-β法

最後に Hughes は人工知能のゲーム探索を例に取る。ゲーム木を構築する gametree、各局面を静的評価する maptree static、指定深さで枝を刈る prune 5、得点を集約する maximizeminimize をパイプラインのように繋ぐことで、ミニマックス探索が組み立てられる。遅延評価のおかげで必要な部分だけが計算され、メモリ効率も良い。さらに α-β 枝刈りは、minimizemax と最小値計算に分解し、途中で閾値を下回ったら残りを打ち切る minleq を導入することで実現される。有望な枝を先に見る並び替え(highfirst)、探索幅の制限(taketree 3)、局面に応じた枝刈り深さの変更(dynamic)といった改良も、すべて独立した関数として後から追加でき、モジュール性の高さが存分に発揮される。

結論

生産性向上の鍵はモジュール化であり、モジュール化を支える糊の品質こそが言語の優劣を決める。関数型言語が提供する高階関数と遅延評価は、従来の言語では不可能だった仕方でプログラムを分解し再結合することを可能にする。とりわけ遅延評価は単なる「効率化のおまけ」ではなく最も強力な糊であり、第一級の機能として扱われるべきだ、と論文は締めくくる。


論評

本論文の独創性は、関数型プログラミングを「何ができないか」ではなく「何ができるか」で擁護し直した点にある。副作用の不在や参照透過性といった当時から繰り返されてきた説明を退け、議論の軸をモジュール性という積極的価値へ移したことで、関数型プログラマーに対して「小さな部品に分け、糊で結合せよ」という実践的な指針を与えた。構造化プログラミングの歴史との類推は、論争的なテーマを冷静な工学的視点へ引き戻す説得力を持つ。

数値計算からゲーム探索まで、性質の異なる題材で同一の主張(生成器と選択器の分離、高階関数による骨格の抽出)が一貫して機能することを示した構成も巧みである。とりわけ遅延評価を「最も強力な糊」と位置づけ、無限リストやループ本体と終了条件の分離という具体例で裏づけた点は、後年の関数型言語設計やストリーム処理の思想に通じる。

発表から30年以上を経て、map/filter/fold や遅延ストリームは多くの主流言語に取り込まれ、本論文の主張の多くは常識となった。それでもなお「言語の価値はその糊の表現力で測られる」という視座は、新しい抽象やパラダイムを評価するときの普遍的な物差しとして参照価値を失っていない。関数型プログラミングの入門・擁護文献として、今日でも最初に挙げられる古典の一つである。