SB-Prologを使う

たけおか@AXE (ex.山本ナヲミ)

%% これは、筆者が
技術評論社 刊 ソフトウェアデザイン誌
「つこてなんぼのFreeBSD」
1998年11月
に掲載した原稿をもとにしたものです %%

0. はじめに

Lispと同じくPorlogも人工知能用の言語として、1980年代には大いに利用さ れました。
Prologは1980年代に産まれた新しい言語で、計算の原理が推論に基づいて います。つまり、Prologのプログラムは一階述語論理の論理式で記述し、計算 の実行は、その論理式を論理推論することと同じです。


	人間(ソクラテス).		% ソクラテスは人間である
	死ぬ者(X) :- 人間(X).		% 人間であるような X ならば 死ぬ
 
を知識データベースに入れ、


 ?- 死ぬ者(ソクラテス).
 
という問い合わせを発行すると、ソクラテスは死ぬという結論が得られます。
ここでは、
 ソクラテスは人間である。
 人間なら死ぬ。
 よって、ソクラテスは死ぬ。
 
という三段論法を一回実行していることになります。
そこで、Prologは知識情報処理のできる、高級言語であるといわれています。
実際には、Prolog処理系は、それを逆向きに推論します。よって、Prologを プログラミング言語として見た場合に、実行をサブルーチンの呼び出しとして 見れば、
 死ぬ者 -> 人間
 
という順序で、通常のプログラミング言語と違和感なく使用できます。
Prologは、通産省の、第5世代コンピュータ(知識処理を行うとされた)開発計 画の中核言語にもなり、日本は世界でも有数のProlog使用国です。
Prologは、研究用に作られた処理系がたくさん有り、産まれが新しいので、 フリーに配られているものも多くありました。
しかし、最近ではどのProlog処理系も開発が止まっており、 Intel系のUNIX ですぐに動く処理系はほとんどありません。
今回紹介するSB-Prologは現在でも簡単に動かせる処理系です。
なお、今回使用したOSはFreeBSD2.2.2とFreeBSD2.2.5です。


1. SB-Prolog

SB-PrologはStony BrookにあるSUNYのDavid WarrenとSuzanne Dietrichによっ て作られ、メンテナンスがアリゾナ大学に移って、現在に至ります。とはいえ、 1987年以来まったく変化がありません。
SB-Prologの作者であるDavid Warrenは、Prologを効率よく実行するためには、 こういうアーキテクチャのコンピュータがあればよい、という、 「Warrenの抽象機械(Warren's Abstract Machine=WAM)」 を考案した人です。

WAMは最初はPrologコンパイラのために考えられたのですが、WAMは Prolog実 行の本質をついていたので、WAM以降、Prologマシンのアーキテクチャは強く WAMの影響を受けます。
日本で第5世代計算機を研究していたICOTのPrologマシンも、WAM以降はWAMを モディファイしたものになっていきます。
SB-PrologはそのWarrenが作った処理系なので興味深いものがあります。
SB-Prologには、コンパイラもありますが、そのオブジェクトは、WAMをター ゲットとしたものになっています。
そして、SB-Prologの実行系は、実は、WAMのインタープリタです。
つまり、CでWAMの仮想マシン・インタープリタを記述し、実行はWAMインター プリタが行います。
また、SB-Prologでは、そのほとんどの機能がPrologで記述してあります。
SB-Prologでは、Prologのコンパイルがネイティブな機械語でなく、WAMへの コンパイルなので、実行速度に不満はあります。とはいえ、前回のGCL(KCl)と 同様、ネイティブ・コードへのコンパイリングでないおかげで、この時代でも 簡単に使用できるのです。
普通のスペックのPrologが、手軽に使えるのですから、多少のオーバヘッド は我慢するしかないでしょう。
なお、SB-PrologはPrologの標準的な文法であるDEC10 Prologに準拠していま す。
有名なC-PrologやQuintus-Prologともほぼコンパチブルです。



2.コンパイル

SB-Prologは

ftp://ftp.cs.arizona.edu/sbprolog/v3/

よりgetします。
最新というよりは、最終版である、Ver3.1が得られます。
makeはsim/で行います。
simはWAMのシミュレータ(仮想マシン・インタープリタ)です。
最近のUNIXでSB-Prologを使用するには、アーカイブを展開した後、 sim/Makefileを Makefile.patch のように変更します。

この後、

	% cd sim
	% make
 
すると、simとbuiltinがmakeされ、sim/sbprologができあがります。



3. SB-Prologの動かし方

sim/sbprologが実行ファイルです。しかし、これは仮想マシンだけで、ユーザ と対話する機能などは入ってません。
そこで、sbprologの引数として、仮想マシンが実行すべきプログラムを指定し てやります。
通常は、そこで指定するプログラムにユーザと対話するためのトップレベルを 指定します。
また、標準的なPrologに組み込みの述語も外部ファイルとなっているので、そ れらのサーチパスを環境変数SIMPATHに指定しておきます。最低限、SB-Prologが 標準で持っているライブラリ(cmplib, modlib, lib)を設定しなければ、Prolog 処理系として実用的ではありません。SIMPATHには複数のディレクトリを':'で区 切って指定できます。
ここでは、SB-Prologを、/src/sbprologV3に展開してあるとします。


% setenv SIMPATH /src/sbprologV3/cmplib:/src/sbprologV3/modlib:/src/sbprologV3/lib:.
% sbprolog '/src/sbprologV3/modlib/$readloop'
SB-Prolog Version 3.1
| ?-
 

となれば、正常に起動しています。
| ?-」はプロンプトです。
節の定義は対話的にも可能ですが、非常に繁雑なので、プログラム・ファイル をロードするのが簡単です。
エディタで次の様なファイル append.prolog を作成します。

--- append.prolog

%% Append

append([],X,X).
append([A|X],Y,[A|Z]):- append(X,Y,Z).
 
--- ここまで

では、SB-Prologにロードしましょう。

| ?- consult('append.prolog').
yes
| ?-
 
となります。
さて、appendを実行します。

| ?- append([a,b,c], [x,y,z], X).

X = [a,b,c,x,y,z]    ここで一旦停止するので、「return」を入力
yes
| ?-
 
と、2つのリスト[a,b,c]と[x,y,z]がつながれています。
通常のプログラミング言語ならこれでおしまいですが、Prologの高級さは、こ れだけではありません。

| ?- append(X,Y,[a,b,c,d]).

X = []
Y = [a,b,c,d];    ここで一旦停止するので、「;」「return」を入力

X = [a]
Y = [b,c,d];

X = [a,b]
Y = [c,d];

X = [a,b,c]
Y = [d];

X = [a,b,c,d]
Y = [];
no
| ?-
 
このように、答を入れると問題が出るという、はなれ技。
Prologの実行はあくまで論理式の正しさに依っているので、双方向の実行が可 能なのです。
途中の入力は、「;」を入力すると、ORを意味し、別な解を求めに行きます。もうそれ以上の解答が必要ない場合は、単に「return」を入力して探索を打ち切ります。

DEC10 prolog系では、変数は大文字で記述し、定数は小文字で記述します。
また、
append([A|X],Y,[A|Z]):- append(X,Y,Z).
で使用している、[A|X]は、リストのcarとcdrを分解してパターンマッチさせる 記述で、この場合、変数Aにリストのcarが変数Xにcdrがマッチしてバインドされ ます。
さて、ソクラテスの例もできます。 socrates.prolog (SB-Prologは漢字は使えないので英語です)

--- socrates.prolog

human(socrates).
mortal(X) :- human(X).
 
---ここまで
実行は

| ?- consult('socrates.prolog').
yes
| ?- mortal(socrates).
yes
 

ということで、ソクラテスは死ぬことが判ります。:-)
また、算術演算もできます。 fact.prolog

--- fact.prolog

%% fact

fa(0,1) .
fa(N,X) :- N1 is N -1 , fa(N1,X1),X is X1 * N .
 
---ここまで
実行は

| ?- consult('fact.prolog').
yes
| ?- fact(6,X).

X = 720
yes
 

ということで、階乗も計算できます。
isは単一方向の代入であり、
N1 is N-1
は、 Cで書く
N1=N-1;
と同じ意味です。
また、算術四則演算子は中置き記述が可能です。


コンパイルも可能です。
complie(ソースファイル名 , オブジェクト・ファイル名)
とします。
一度、インタープリタで定義を行ったものは、コンパイル後は、loadしなけれ ばなりません。

| ?- compile('append.prolog', 'append').

Compile : append.prolog => append
compilation complete -- 0.11 secs
yes
| ?- load('append').
yes
| ?- append(X,Y,[a,b,c,d]).

X = []
Y = [a,b,c,d];
	(以下略)
 

SB-Prologは、内部でみつからなかった述語については、SIMPATHに従って、自 動的に機械語ファイルをサーチし、ロードします。
よって、自動的にロードして欲しい述語は、そのファイル名と述語名を一致さ せておかねばなりません。そうしておけば、自分で定義しコンパイルした述語が、 自動的にロードされ、非常に便利です。
SIMPATHにカレント・ディレクトリ(.)を入れておけば、コンパイルして、即座 に述語として自動ロードさせることができます。



4. より便利に

より便利にSB-Prologを使用するために、
setenv SIMPATH /src/sbprologV3/cmplib:/src/sbprologV3/modlib:/src/sbprologV3/lib:.

は、.cshrcなどに記述しておくべきでしょう。
また、/usr/local/bin/prologなどとして、 次のようなshellスクリプトを用意すると便利です。
--- /usr/local/bin/prolog

#!/bin/sh
/src/sbprologV3/sim/sbprolog /src/sbprologV3/modlib/\$readloop
 
---


emacs(mule)からprologを起動すると非常に便利です。
emacsに標準のprolog.elは、元富士通研究所の梅田さんが書かれたものなので すが、C-PrologとQuintus Prolog用のもので、SB-PrologにはLisp変数の初期値 が不適当です。
そこで、.emacsなどに
---

(setq prolog-consult-string "consult(user).\n")
(setq prolog-eof-string nil)
---
と記述します。
そしてmuleを起動したのち、M-x run-prologとして、prologを起動します。
その後、M-x 2 で窓を2つに分割し、片方でソースを編集すると非常に便利です。



そして、ソースを編集している窓から、簡単なキー操作で、Prolog処理系へソー スを読み込ませることができます。
その方法は、

  1. 送り込みたい節の頭でマーキング(C-space)を行う
  2. 送り込みたい部分の最後にカーソルを移動
  3. M-C-x (ESC,C-x)を押下

すると、指定したリージョンが自動的にconsultされます。
これで、もう、Prologマシンは不用になりましたね。:-)
emacsのprologモードでは、インデントを自動的につけてくれます。
Prologのコメントは「%」で開始した行です。
emacsのprologモードの場合、%%がパラグラフの開始で、%は通常のコメントです。

5. マニュアルの見方

SB-Prologにはsbprolog_doc.meという、非常に詳しいマニュアル・ファイルが あるので、それを読めばすべてわかります。
ただし、テーブルなどが入ったroffファイルなので、それをキャラクタ端末で 読むには、

 % tbl sbprolog_doc.me |nroff -me |col
 
としなければなりません。
こうすれば、lessなどで読める形になり、オンラインで検索できるので、非常 に便利になります。


--- EOF
たけおか(竹岡尚三)のPrologページ 目次