全学計算機システム上でのSWI-Prologの使い方(暫定版)

Prologの処理系には様々なものが存在する。 本稿では無償で利用できるSWI-Prolog の利用手順について説明する。


SWI-Prologについて

SWI-Prologは多くのUNIXやMS-Windows で利用することが出来るエジンバラProlog (DEC-10 Prolog) 記法を採用したProlog処理系であり、ISO規格 にも準拠している。 本稿では阪口が筑波大学学術情報メディアセンターの 全学計算機システムの Linux環境(以下ichoと記す)にインストールした処理系の 使い方について説明する。

なお、SWI-PrologのホームページのURLは http://www.swi-prolog.org/ である。自分のPCなどで使用したい場合は、そちらからダウンロードして インストールすれば良い。MS-Windows版のバイナリパッケージはインストーラを 含んでいるので、簡単にインストールできる。

ichoにインストールしたSWI-Prologのバージョンは6.2.3であり、日本語など Unicode文字に対応している。ichoの場合、デフォルトのUTF-8や各種localeの設定 に応じて日本語などの文字を使うことができる。


SWI-Prologのマニュアル

オンラインマニュアルはSWI-Prologのホームページでも提供されているが、 履修者の便宜のため、あらかじめダウンロードしたものを以下のリンクから 辿れるようにしたので、活用してもらいたい。


利用手順

SWI-Prologはichoの阪口のホームディレクトリの下に インストールしている。そのため、ichoの標準環境では コマンドとして実行する際に、絶対パス形式で指定するか、各自の環境設定を 変更する必要がある。SWI-Prologでプログラムを実行する時の手順はおおよそ 以下のような流れになる。

  1. ichoにログインする。
  2. テキストエディタでソースプログラムを入力・編集し、 ファイルに保存する。
  3. SWI-Prologを起動する。
  4. ソースプログラムを読み込ませる。
  5. 質問式を入力し、プログラムを実行する。
  6. SWI-Prologを終了する。
  7. ichoをログアウトする。

なお、SWI-PrologはUNIXコマンドとして起動するので、GUI環境で ログインした場合はターミナルエミュレータ(例: GNOME端末)を開く必要がある。 ssh などでログインした場合はそのまま使用することができる。

SWI-Prologの起動と終了

ichoにインストールしたSWI-Prologの起動コマンドは

~sakaguchi.tetsuo.gf/pub/bin/swipl (または /home/sakaguchi.tetsuo.gf/pub/bin/swipl)

である。起動すると何行かのメッセージが表示された後、SWI-Prologの プロンプトとして「?-」が表示される。

プロンプト「?-」が表示されている時に質問式を投入すると、 それに応じたプログラムや組み込みの機能が呼び出され、処理が行われる。

SWI-Prologを終了するには質問式として「halt.」を投入する。 すると、SWI-Prologが終了して UNIX のシェルの のコマンドプロンプトが表示され、UNIXのコマンド入力ができるようになる。

プログラムの入力

プログラムは起動したSWI-Prologに対してキーボードから入力することも できるが、通常はテキストエディタ(例えば、vi (vim)emacs、GNOMEのGUIテキストエディタなど) を使ってプログラムを入力・編集し、テキストファイルに保存する。 そして、SWI-Prologでそのファイルからプログラムを読み込んで 実行するという流れになる。

プログラムを保存するファイルの名前は拡張子を「.pl」とすると、 Prolog中でファイル名を指定する際に拡張子を省略することができる。 ファイル名にピリオド(.)が含まれる際はシングルクォート (')で囲まなければならないので、拡張子を 「.pl」にしておく方が良い。なお、Perlのプログラムでも同じ 拡張子を用いていることが多いので、混乱を避けるためにはディレクトリで 分類すると良いと思われる。

ファイルに入力したプログラムを読み込むためには組み込み述語の consultを用いる。例えば、

consult(abc).

という式を入力するとファイル「abc.pl」からプログラムを 読み込む。このconsultには略記法が準備されており、

[abc].

でも上と同じ意味になる。もし、拡張子を省略せずに指定するとすると、

consult('abc.pl').

または、

['abc.pl'].

と書くことになる。

(注: icho における vi (vim)はデフォルトで様々な言語の構文を解釈し、 色付けなどするモードになっている。拡張子などの問題があるためか、 Prolog用の機構がうまく動かないこともあるので、その場合は、 「:syntax off」として、その機能を停止すると良い。)

プログラムの実行

プログラムを読み込ませた後、実行するためには適切な質問式を 投入する。C言語などではメインプログラム(main関数)が決まっているが、 Prologにはそのようなものはなく、プログラミング時に決めた適切な式を 投入することになる。例えば、述語名が「abc」で、3つの引数 「x」、「y」、「z」を指定する場合は、

abc(x, y, z).

という式を投入することになる。

プログラムの実行時は特に指定した場合を除くと画面への表示はその式に 関して推論した結果となる。結果は大きく分けて3通りあり、 「true」、「false」、引数に指定した変数の値、 のいずれかになる。最後の場合は 変数に適切な値の候補が複数の場合もあるため、

X = 10

のような表示のすぐ右にカーソルが表示されたままになり、プロンプトが 表示されない。これは変数の値がこれで構わないかの判断を求めている 状態なので、問題なければそのままエンターキーを押せばプロンプトに 戻る。他の値を求めさせたい場合にはセミコロン(;)を押せば、 別解を求め、その結果を同様に表示する。セミコロンを押す度に別解を 求めるが、最後の解を表示するとプロンプトに戻る。

実行のトレース

Prologのプログラムの実行は、他の手続き型言語と大きく様子が異なる ので、動作の理解やデバッグのためにはトレースが有効である。 プログラムの実行をトレースしたい場合は 組み込み述語のtraceを用いる。例えば、

trace(fact).

を投入すると、述語factの呼出しとリターンの様子が引数と返り値も 含めて画面に表示される。トレースをする際はデバッグモードに入っているので、 トレースを止めるには、以下のように組み込み述語nodebug を用いてデバッグモードを止めれば良い。

nodebug.

なお、トレースする場合、変数名はプログラムを入力・編集したものと 異なる名前となっている点に注意が必要である。

GUI環境における実行のトレース

教育用計算機システムの端末をLinuxで起動して、GUI環境で使う場合には GUIのトレーサを使用するとより解かりやすい。GUIのトレーサは以下のように 組込み述語を使用すると動作する。

gtrace.

GUIのトレーサではステップ実行になるので、ツールバーの一番左の下向き 矢印などをクリックして、実行を進める必要がある。 詳細な使い方に関してはマニュアルの3.5等を参照すること。

なお、トレースをやめる際は

notrace.

を実行する。

実行速度の計測

質問式を与えて、結果を得るまでにかかる時間を計測することもできる。 これには組み込み述語の timeを用いる。

time(質問式).

とすると、その「質問式」の結果を得るのにかかった時間が 結果とともに表示される。

実行画面を残すには

プログラム実行時の画面出力をファイルに残すには UNIX のコマンド scriptを用いるのが一般的である。使い方は単に scriptと投入すると、開始した旨の表示がされ、 終了するまでに画面に表示された文字をすべて ファイル「typescript」に保存する。そこでは普通にUNIXのコマンド を実行することができるので、SWI-Prologの実行の様子も記録することができる。 終了する場合は「exit」 というコマンドを実行する。終了すれば元のUNIXプロンプトに戻る。

icho(というかLinux)ではUNIXプロンプトその他にゴチャゴチャ余分な情報を 付与するように設定されていることが多く、こうしてできたファイル typescriptはそのまま印刷したりテキストエディタで必要な 部分のみを抜粋するのは面倒である。これを避けるにはホームにある .bashrcファイルの末尾などでプロンプト関係の変数を設定 してやれば良い。もしくは、scriptではなく端末エミュレータの 画面コピー機能を用いるという方法もあるが、ここでは個別の手順は 示さないので、各自で調べて欲しい。

その他

なお、現在のSWI-Prologに読み込ませたプログラムの内容を見る場合は、 組み込み述語listingを用いる。例えば、

listing(abc).

とすると、述語abcを定義する文(節)の一覧が表示される。述語名を略して

listing.

とするとその時SWI-Prologで読み込んでいるプログラムすべてを表示する。

なお、SWI-Prologでは変数名が元のプログラムとは違う名前に付け替えら れているので注意が必要である。

なお、SWI-Prologの起動コマンドの投入を楽にしたい場合は、 UNIXの入門書などを参考にichoの自分のホームディレクトリにある 「.bashrc」ファイルを編集し、その中でPATHを設定するか、 aliasを設定すれば良い。


実行例

ここではSWI-Prologの起動、プログラムの読み込みと実行、そして終了の 流れの一例を示す。ここで使っているプログラム例「fact.pl」 は階乗を求めるものであり、ファイルの中身は以下の通りである。

% fact.pl - basic factorial

fact(N, 1) :- N < 1, !.
fact(N, X) :- N1 is N - 1,
    fact(N1, Y),
    X is N * Y.

これを実行する流れは例えば以下のようになる(scriptで 記録したものを示す)。

スクリプトは 2012年12月11日 13時28分11秒 に開始しました
[sakaguchi.tetsuo.gf@unix01 zemi13]$ ~sakaguchi.tetsuo.gf/pub/bin/swipl
Welcome to SWI-Prolog (Multi-threaded, 32 bits, Version 6.2.3)
Copyright (c) 1990-2012 University of Amsterdam, VU Amsterdam
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to redistribute it under certain conditions.
Please visit http://www.swi-prolog.org for details.

For help, use ?- help(Topic). or ?- apropos(Word).

?- [fact].
% fact compiled 0.00 sec, 3 clauses
true.

?- listing.

:- thread_local thread_message_hook/3.
:- dynamic thread_message_hook/3.
:- volatile thread_message_hook/3.


fact(A, 1) :-
        A<1, !.
fact(A, C) :-
        B is A+ -1,
        fact(B, D),
        C is A*D.
true.

?- fact(10, X).
X = 3628800.

?- fact(1, 1).
true.

?- trace(fact).
%         fact/2: [call,redo,exit,fail]
true.

[debug]  ?- fact(5, X).
 T Call: (6) fact(5, _G337)
 T Redo: (6) fact(5, _G337)
 T Call: (7) fact(4, _G445)
 T Redo: (7) fact(4, _G445)
 T Call: (8) fact(3, _G448)
 T Redo: (8) fact(3, _G448)
 T Call: (9) fact(2, _G451)
 T Redo: (9) fact(2, _G451)
 T Call: (10) fact(1, _G454)
 T Redo: (10) fact(1, _G454)
 T Call: (11) fact(0, _G457)
 T Exit: (11) fact(0, 1)
 T Exit: (10) fact(1, 1)
 T Exit: (9) fact(2, 2)
 T Exit: (8) fact(3, 6)
 T Exit: (7) fact(4, 24)
 T Exit: (6) fact(5, 120)
X = 120.

[debug]  ?- nodebug.
true.

?- fact(5, X).
X = 120.

?- halt.
[sakaguchi.tetsuo.gf@unix01 zemi13]$ exit
exit

スクリプトは 2012年12月11日 13時29分29秒 に終了しました

by Tetsuo Sakaguchi <sakaatslis.tsukuba.ac.jp>
$Date: 2012/12/11 04:49:10 $ (UTC)