Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【ITニュース解説】The Expression Problem and its solutions

2025年09月09日に「Reddit /r/programming」が公開したITニュース「The Expression Problem and its solutions」について初心者にもわかりやすく解説しています。

作成日: 更新日:

ITニュース概要

プログラムに新しい種類のデータと、そのデータを扱う新しい機能を追加したい時、両方を既存コードの修正なしで実現するのは難しい。この「式問題」と呼ばれる課題と、それを解決する様々なプログラミング手法を紹介する。(120文字)

ITニュース解説

ソフトウェア開発において、プログラムの拡張性は非常に重要な要素である。「式の問題(Expression Problem)」とは、この拡張性に関する根源的な課題の一つを指し示す言葉だ。具体的には、データ構造の体系とそのデータ構造に対する操作の体系という二つの要素を、互いに独立して拡張することをいかにして実現するか、という問題である。多くのプログラミング言語や設計手法では、データ構造の種類を増やすことと、それに対する操作の種類を増やすことのどちらか一方は容易にできるが、両方を同時に容易に行うことは難しいというトレードオフが存在する。

この問題を理解するために、数式の計算を例に考えてみよう。まず、「数値」と、二つの式を足し合わせる「加算」という二種類のデータ型が存在するとする。そして、これらの式を評価して結果を計算する「評価(eval)」という操作を定義する。ここからプログラムを拡張していくことを考える。拡張には二つの方向性がある。一つは「乗算」や「減算」といった新しい種類のデータ型を追加すること。もう一つは、式を文字列に変換する「表示(print)」や、式を最適化する「簡約化(simplify)」といった新しい種類の操作を追加することだ。

まず、関数型プログラミングのアプローチを見てみよう。このアプローチでは、データ型を列挙型や代数的データ型として定義し、操作をパターンマッチングを用いた関数として実装することが多い。この場合、新しい操作を追加するのは非常に簡単である。例えば、新しく「表示」操作を追加したい場合、「評価」関数とは別に「表示」関数を一つ定義し、その中で「数値」の場合の処理と「加算」の場合の処理を記述すれば完了する。既存のデータ型の定義や他の関数に手を入れる必要はない。しかし、このアプローチでは新しいデータ型を追加することが困難になる。「乗算」という新しいデータ型を追加する場合、既存のすべての関数、つまり「評価」関数と「表示」関数の両方を修正し、「乗算」の場合の処理を追記しなければならない。操作の数が増えれば増えるほど、修正箇所は広範囲に及び、プログラム全体の再コンパイルも必要となる。

次に対照的なアプローチとして、オブジェクト指向プログラミングの考え方を見てみよう。こちらでは、まず共通のインターフェース(あるいは抽象基底クラス)を定義し、個々のデータ型をそのインターフェースを実装するクラスとして表現する。操作はインターフェースで定義されたメソッドとして各クラスに実装される。このアプローチでは、新しいデータ型の追加が非常に容易だ。例えば「乗算」クラスを追加したい場合、共通のインターフェースを実装した新しいクラスを一つ作成するだけで済む。既存のどのクラスにも変更を加える必要はない。その一方で、このアプローチは新しい操作の追加を困難にする。もし「簡約化」という新しい操作を追加したくなった場合、まず共通インターフェースにそのメソッドを追加し、さらにそのインターフェースを実装しているすべての既存クラス(「数値」クラス、「加算」クラスなど)に、その新しいメソッドの実装を追加して回らなければならない。これは大規模な変更となり、保守性を損なう原因となる。

このように、関数型アプローチは操作の追加に強くデータ型の追加に弱く、オブジェクト指向アプローチはデータ型の追加に強く操作の追加に弱いという、二律背反の関係にある。「式の問題」の核心は、このトレードオフを克服し、データ型の追加と操作の追加の両方を、既存のコードを一切変更することなく、安全かつ容易に行える仕組みをいかにして提供するかという点にある。この課題に対する解決策は、長年にわたり多くの研究者や開発者によって探求されてきた。

その解決策の代表例として、いくつかの手法が存在する。オブジェクト指向言語でよく用いられる「ビジターパターン」は、データ構造と操作を分離するためのデザインパターンである。これにより、データ構造のクラス階層を変更することなく、新しい操作を追加することが可能になる。また、一部の言語がサポートする「多重ディスパッチ(マルチメソッド)」という機能は、呼び出すべき処理を、関数の引数となるオブジェクトすべての型を考慮して動的に決定する仕組みであり、データと操作をより柔軟に組み合わせることができる。さらに、Haskellのような関数型言語で用いられる「型クラス」は、既存のデータ型に対して後から新しい振る舞い(操作の集合)を定義し、適用することを可能にする強力な仕組みであり、「式の問題」に対するエレガントな解決策の一つと見なされている。

「式の問題」は、単なる理論上のパズルではなく、ソフトウェアの設計において常に直面する現実的な課題である。システムを開発する際には、将来的にデータ構造と操作のどちらがより頻繁に拡張されるかを予測し、それに適した言語機能や設計パターンを選択することが、柔軟で保守性の高いソフトウェアを構築する上で極めて重要となる。この問題意識を持つことは、より優れたシステムエンジニアになるための重要な一歩と言えるだろう。

関連コンテンツ

関連ITニュース