[制約プログラミング落穂拾い] 宣言性の光と影(2)
さて今回は、制約プログラミングの最大の特徴であり、メリットであるはずの「宣言性」、問題の定義と問題の解法の分離が、ソフトウェア開発の現場でどのような意味合いを持つかを具体的に考えて行きたいと思います。
なお、制約プログラミングのさまざまな機構の実装は処理系により異なります。従って具体的な機構の説明の部分は、あくまでも例示に過ぎないことを予めお断りしておきます。例示にあたっては、(当然のことですが)自分が実装を知っている処理系を前提としています。
宣言的なプログラミングでは、プログラムは問題を解くための処理の手順を書くのではなく、問題に存在する制約、即ち変数の間の関係を記述するだけです。
制約の記述をするためのシンタクスは制約プログラミングの環境により異なりますが、ここでは例えばC言語によるライブラリを想定します。この場合、
- 制約が設定できる変数型が提供され、その型の変数あるいは変数の配列を
生成する関数が提供されます。 - 変数間に制約を設定するための関数が提供されます。
- 設定された制約を充たす変数の値の組を求めるための関数が提供されます。
そしてこれらを概ね上記の順番に用いて問題を解くことになります。つまり変数を生成し、制約を設定し、解を求めるという流れのCのプログラムを書くことになります。
そして「原理的には」(あえて括弧書きにした理由にはいずれ触れることになると思います)解くべき問題に存在する制約をどのような順序で記述しても構いません。
制約プログラミングライブラリのチュートリアルにあるような簡単な例題では、パズルのような問題を解くために数個の変数ないし変数の配列に、数個の制約を設定して解を求めるプログラムを書くことが多いでしょう。
そのプログラムを理解し、似たような例題を解くための簡単なプログラムを書くのはそんなに難しくないかも知れません。
ところが現実の問題を解こうとすると、些か勝手が違ってくることが多いようです。
課題が幾つも出てきて、しかもそれらは制約プログラミングを用いない開発では直面することがないような性質のものなのです。
課題は大きく分けて以下の2つに集約されると思います。
- 現実の問題を、用意された制約の組み合わせで表現することができるだろうか。
つまり制約記述の表現力やモデリングの巧拙の問題があります。 - 問題を表現できたとして、解をうまく求めることができるだろうか。
ここで「うまく」というのには、(a)実用上許容できる時間内に、(b)実用上許容できる品質の解を求める、という2つの側面が含まれます。
これらはいずれもどんなプログラミング・パラダイムでも直面する課題ではあるでしょう。
ライブラリを使うのは、ある処理をやるための手間を省くためですが、ライブラリが思い通りに動かなければ、ちょっとした工夫が必要になったり、最悪の場合にはある部分だけはそのライブラリを使うことを諦めるような対応を迫られることはしばしばあるでしょう。
ですから制約プログラミングライブラリを使うときにも丁度同じことが起きているに過ぎない、という見方もできるかとは思いますが、そうした対応をする際に、制約プログラミングの場合には「宣言性」という特徴が大きく影響してくるのです。
こうした見方をした場合には、「宣言性」は問題を解くための処理手順を全てブラックボックス化してしまうことに相当します。意識せずに済むならばブラックボックスは大きい方がいいのですが、意識しないといけないとなるとそれが
融通の利かなさに転化しかねないのです。
簡単に言ってしまえば、「問題を解くための処理の手順を自分で明示的に書くことができない」という制限と戦いながら課題を解いていくということになるのです。簡単な例題を解いているうちはともかく、実用的な問題に取り組めば、ほぼ不可避的に、こうした状況に直面しながら開発を進めていくことになります。
次回は更に具体的に、今回述べた課題の中身を見て行くことにします。
それは同時にブラックボックスであるはずの「宣言性」の裏側にある「処理の流れ」を覗き込むことになります。「宣言性」という触れ込みは現実には掛け声倒れなのか、という声が聞こえてきそうですが、ある道具をうまく使いこなすためには、その道具の仕組みをある程度わかっているほうが良いでしょう。勿論、そうしたノウハウなしで使えるような方向を目指すべきなのかも知れませんが、道具の癖を理解し、使いこなすコツが掴めれば威力を発揮するのであれば、実用上は充分なのだと考えることもできるのではないでしょうか。