Prologの述語の書き方

Prologは「実行速度遅い」、「書きにくい」*1、「古い」*2と、三重苦な言語ですが、非常に便利で面白い言語です。

特に面白い点が、「リアルタイムに自分自身のプログラムを『手軽に』書き換え可能」*3という点です。ものすごく簡単な例を書くと、

?- hoge(a).
No
?- assert(hoge(a)).
Yes
?- hoge(a).
Yes

こんな感じで、hoge(a)が有効になります。

さて、少々脱線してしまいましたが、Prologで述語をどう書くかと言うことです。
Prolog には Unification という機構があり、それは「不確定な変数を保持したまま処理を進め、確定したときに初めてその変数の値が決まる」というものです。たとえば、以下のように処理の途中まで変数の中身が決まらないままに処理を進めることが可能です。

%プログラム ここから
hoge(X):-
  foo(X).

foo(X):-
  bar(X).

bar(a).
%ここまで

?- hoge(X).
Call:hoge(G_001). %未確定
Call:foo(G_001).  %未確定
Call:bar(G_001).  %未確定
Exit:bar(a).      %決定 X=a
Exit:foo(a).
Exit:hoge(a).

X=a

Yes
?-

まあ、ニュアンス的にはこんな感じ。それを利用した方法としての述語の記述方法があるわけです。そうして、大まかに述語の記述方法は二つあります。

  1. 本当の述語(論理学上)としての書き方
  2. 関数としての書き方(λ計算的)

1の書き方は、「現在ある規則と事実を使い、求めている事実が演繹可能かどうか」を記述するものです。先の例で云うと、

?- hoge(a).

インタープリターに投げるに等しい。

もう一つの「λ計算的書き方」と言うのが、入力と、出力のための変数を引数に持ち、処理によって値が出てくるのを期待する書き方です。詰まり、

?- hoge(a,X).

という書き方。これは「X=hoge(a)」と似ています。

Prologは一階述語論理を基本としています(SWI-Prologだと「=..」なんていうMeta Predicateもあるんで嘘だけど)。したがって、前者の方の書き方が一番正しいわけですよ。言い換えると、

Predicate(x) : xはPredicateである

という書き方をすべきであって、

Predicate(x,y) : Predicate(x)=y

と云う書き方をすべきでないと思うわけです。したがって、

「使う値は、源泉からそのとき作る」

と言うこと。……しかし、まあ、プログラムの世界そうそううまくいく分けじゃないのです。なぜなら、

  1. そうすると処理量が増える。
  2. 統一的な処理がやりにくい。

と言う問題があるのです。

どちらが良いのか未だに答えが出ません。

*1:ただし、慣れたら書けます

*2:古いけど新しいとも云う

*3:確かに一度テキストに落とし、Forkしてコンパイル&実行 or インタプリターに再読込、ParentをInitにしてKillすれば同じことはできる