リスト●Prologのソースコード
ここでは図4で示す迷路を解くプログラムを掲載した。1985年8月号BYTE誌に掲載したものを本誌で変更を加えたもの。Cuadrado, C. Y., Cuadrado, J. L.,“Practical Prolog,”BYTE,pp.151-158,vol.10, no.8.

関係の定義だけなら「推論」が必要

 オブジェクト指向を突き詰めて考えれば,オブジェクトの関連を定義するだけでシステム記述が完了するのが理想だろう。だが現実問題として,オブジェクト指向プログラミングの枠組みでは実現できない。この「関係」に基づいて実行するための「推論エンジン」が必要となる注2)

 プログラミング言語でこれを備えていたのが,宣言型言語と呼ばれるものである。1980年代前半に流行したPrologがその代表だ。Windowsで動作するProlog処理系としては,GPLで公開されている「SWI-Prolog」(http://www.swi-prolog.org/)がある。商用製品としては,イフコンピュータの「IF/Prolog」,KLS研究所の「K-Prolog」などがある。

 Prologの場合,論理関係に基づいて3段論法の推論を実施する。例えば「AならばB」と「BならばC」という条件から,「AならばCは成立する」と推論する。基本はパターン・マッチング(単一化,あるいはユニフィケーションと呼ぶ)である。これに,一度一致したパターンで再度登録済みの情報を検索し続け,条件を満たすかどうか検証する(バックトラックする)ことによって推論を実現している(図3[拡大表示])。例えば数値計算なども,数値をユニフィケーションすることによって実現している。

 Prologで重要なのは,静的な関係を記述するだけで,その解き方を記述していない点である。例えばリスト[拡大表示]は,迷路を探検するプログラムである(図4[拡大表示])。迷路の構造を定義している部分と,迷路を解くとはどういうことかを定義してる部分があるが,その解き方は記述していない。それでも正しく答えを導き出すのだ(写真1[拡大表示])。

図3●Prologの推論を担うバックトラック
解候補を生成し,すべてのゴールを満たすかどうかを判定する。ゴールを満たさない場合は解を廃棄して,別の新しい解候補を生成する。この一連の動作がバックトラックである。この仕組みと論理的に同一と見なせるものを等価に扱う(ユニフィケーション)によって,推論を実現する。
 
図4●対象とする迷路
この位置関係(つながり)がPrologのプログラムで定義されている。Cuadrado, C. Y., Cuadrado, J. L.,“Practical Prolog,”BYTE,pp.151-158,vol.10, no.8.

 これだけだと数値計算ができないように思われるかもしれないが,変数に数値を定義した関係に基づいて置き換えて計算する。例えば数列の計算など,まさにそのまま定義すれば実行可能,という感じである(写真2[拡大表示])。ただしPrologはCやJavaなどにおける「関数」は存在しないため,表現上はやや工夫が必要だ。このことから見ても,計算が重要となる処理にはあまり向かないだろう。

 実はいわゆる「AI(Artificial Intelligence)」で最も使われているプロダクション・ルールに基づく推論エンジンも,基本的には宣言に基づいている。PrologがAI言語として注目を集めたのも,ある意味で当然だったのである。

写真1●Prologプログラムの実行結果
正しい経路を発見していることがわかる。K-Prologを使って実行した。
 
写真2●数値計算の例

制約条件を定義するアプローチもある

 一方Prologに似たものとして,制約条件を宣言的に定義しておき,その制約条件を満たす解を導き出すアプローチもある。制約論理プログラミング言語などと呼ばれる。アイザックの「iZ-C」や仏ILOG Software社の「ILOG Solver」などがその一例だ。これらは関係という一つの軸に絞り込んでおり,プログラミングにまつわる「手順」を意識しないという点でわかりやすい。Prologに比べ,数値に重きを置いていると言える。制約論理プログラミング言語は,複雑な条件が絡む工程計画立案などに使われることが多い。

課題はデバッグと説明可能性

 しかし現実には,手続きをプログラムする処理系に比べ,これらは普及していない。まず第一に,性能が出なかったこと。バックトラックが頻繁に発生してしまうと,何度となくデータベースを検索することになる。次にロジックの記述が容易である半面,デバッグしにくい。定義したロジックに基づいて,処理系がどう理解するかをちゃんと想像できないとデバッグできないからだ。一般的な手続き型言語の場合,こういった想像は不要である。そもそも想像が入り込む余地がない。

 また仮にうまく動作したとしても,「なぜうまく動作するのか」分かりにくい。例えばニューラル・ネットワークなどを使って最適化問題がそれなりに解けたとしても,どうしてそれが最適解なのかを説明できないのと同じである。こういった不安感も,普及を妨げる原因だろう。ただ性能面での問題は少なくなっている。再び脚光を浴びるかもしれない。

 いちばん考えやすいのが,手続き的な部分と推論部分を共存させることだろう。既にPrologや制約論理言語をJavaと結びつけて実行する処理系も出てきている。イフコンピュータの「MINERVA」などがこれに当たる。論理や制約だけで記述したい部分にこれらを使い,あとの部分はJavaを使って記述するというアプローチである。また実装形態としてC言語ライブラリとして実装されているものもある。

「へぇー。こんな世界があるんですね」
「うん。昔はこれだけのことを実行するのは性能的にムリがあったんだけどね」
「でも仕様定義だけでプログラムが済めばいいですよね」
「実際にはノウハウはかなりあるんだ。それに,考え方次第という面もあるからなぁ」

(北郷 達郎、八木 玲子)