AZ-Prolog ユーザーズマニュアル

## 10.付属プログラム/資料

### 10-1.ベンチマークプログラム

##### プログラムの格納場所

ベンチマーク起動プログラム一式は次の場所に格納されています。
Makefileがありますので、ディレクトリごと作業場所へコピーしてLinuxではコンパイルしてください。(Windows版ではコンパイル済みです。）

Windows： | %AZProlog%¥bench
Linux： | ${AZProlog}/share/azprolog/bench
Mac： | ${AZProlog}/share/azprolog/bench

##### コンパイル

ベンチマーク用プログラムはSICStus-Prolog様のサイトにあるものを利用します。
http://sicstus.sics.se/performance.html からダウンロードして解凍し、内容物すべてを「bench/source」下へコピーし「bench」下でmakeします。
( Windowsで再コンパイルするときは、 ~/xxxx/bench> nmake )

##### 起動

ターミナルからbenchmarkを起動すると次のメニューが表示されます。
番号または各メニュー項目の頭文字(r,s,l,t,g,b,e)を投入します。
＜例＞

    << AZ-Prolog.V8 BenchMark Test Menu >>

    1) Run  All BenchMark Program (if Added,Parameter File Load)
    2) Save AZ-Prolog-Benchmark-Result to Current Directory
    3) Load All Result-File From Current Directory
    4) Table-Style Result Display
    5) Graph-Style Result Display
    6) Break to Interpreter (Type "?-unbreak." To Return Here)
    7) Exit
    Enter No.>r  <== "r"の投入でベンチマークが走ります

Module名のプログラムを（）内の回数繰り替えした秒数が表示されます。

    ******  Running Benchmark Programs :: AZ-Prolog.V8 ******

    ModuleName  Verify Iterate C-Compile  Byte-Compile  Interpreter   [SWI-Prolog]
    -----------+-CBIO-+-------+----------+-------------+-------------+------------
    boyer       [Tttt]     100 0.796 (1)  1.892 (2.37)  4.970 (6.24)  2.506 (3.14)
    browse      [Tttt]     100 1.319 (1)  2.360 (1.78)  4.375 (3.31)  2.957 (2.24)

「C-Compile」がフルコンパイルコードでの処理時間
「Byte-Compile」がバイトコンパイルコードでの処理時間
「Interpriter」がインタプリタでの処理時間

##### 他社製Prolog処理系との比較

同ディレクトリには他社製Prolog処理系用起動バッチファイル「iso_main_swi.pl」が含まれています。
SWI-Prolog がインストールされているとして、次の手順で結果を“SWI-Prolog.rslt”に出力します。

    ~/xxxx/bench$ swipl
        Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 5.10.4)
        Copyright (c) 1990-2011 University of Amsterdam, VU Amsterdam

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

    ?- [iso_main_swi].

結果は、ベンチマークメニューの「l」コマンドで読み込みます。

    Enter No.>l

    [AZ7-B.rslt,AZ7-C.rslt,AZ7-I.rslt,SWI-Prolog.rslt] Loaded

「t」コマンドでテーブルスタイルで結果の表示をします。

    Enter No.>t

          << AZ-Prolog V8.11 LINUX x64 BenchMark Ubuntu1404 on Core i7-4790k >>

                               <========  AZ-Prolog  ==========>
    ModuleName  Verify Iterate C-Compile  Byte-Compile  Interpreter   [SWI-Prolog]
    -----------+-CBIO-+-------+----------+-------------+-------------+------------
    boyer       [Tttt]     100 0.796 (1)  1.892 (2.37)  4.970 (6.24)  2.506 (3.14)
    browse      [Tttt]     100 1.319 (1)  2.360 (1.78)  4.375 (3.31)  2.957 (2.24)
    chat_parser [Tttt]     100 0.205 (1)  0.691 (3.37)  0.861 (4.20)  0.675 (3.29)
    crypt       [Tttt]   10000 0.428 (1)  1.227 (2.86)  2.295 (5.36)  2.865 (6.69)
    deriv       [Tttt]  100000 0.191 (1)  0.365 (1.91)  0.545 (2.85)  0.495 (2.59)
    dynamic_uni [Tttt]   10000 0.306 (1)  0.817 (2.66)  1.037 (3.38)  0.827 (2.70)
    fast_mu     [Tttt]   10000 0.132 (1)  0.262 (1.98)  0.609 (4.61)  0.525 (3.97)
    flatten     [Tttt]  100000 0.763 (1)  1.881 (2.46)  4.106 (5.38)  3.083 (4.04)
    itak        [Tttt]     100 0.854 (1)  1.069 (1.25)  1.220 (1.42)  1.523 (1.78)
    meta_qsort  [Tttt]    5000 0.433 (1)  0.988 (2.28)  2.302 (5.31)  1.036 (2.39)
    mu          [Tttt]   10000 0.093 (1)  0.196 (2.10)  0.433 (4.65)  0.376 (4.04)
    nreverse    [Tttt]  100000 0.188 (1)  0.350 (1.86)  3.027 (16.1)  1.792 (9.53)
    nreverse_bu [Tttt]  100000 0.191 (1)  0.279 (1.46)  0.444 (2.32)  1.821 (9.53)
    poly        [Tttt]    1000 0.679 (1)  1.330 (1.95)  2.389 (3.51)  2.170 (3.19)
    primes      [Tttt]   10000 0.105 (1)  0.306 (2.91)  0.815 (7.76)  0.777 (7.40)
    prover      [Tttt]   10000 0.124 (1)  0.273 (2.20)  0.603 (4.86)  0.379 (3.05)
    qsort       [Tttt]  100000 0.645 (1)  1.644 (2.54)  3.963 (6.14)  3.161 (4.90)
    queens      [Tttt]   10000 0.143 (1)  0.280 (1.95)  0.981 (6.86)  0.988 (6.90)
    query       [Tttt]  100000 0.496 (1)  1.700 (3.42)  2.231 (4.49)  3.374 (6.80)
    reducer     [Tttt]     500 0.258 (1)  0.741 (2.87)  1.135 (4.39)  0.805 (3.12)
    sendmore    [Tttt]     500 0.395 (1)  1.074 (2.71)  2.971 (7.52)  3.441 (8.71)
    simple_anal [Tttt]     500 0.119 (1)  0.340 (2.85)  0.607 (5.10)  0.438 (3.68)
    tak         [Tttt]    1000 0.955 (1)  2.911 (3.04)  10.33 (10.8)  5.902 (6.18)
    unify       [Tttt]   20000 0.447 (1)  1.470 (3.28)  3.665 (8.19)  2.374 (5.31)
    zebra       [Tttt]     500 0.284 (1)  0.317 (1.11)  0.594 (2.09)  0.717 (2.52)
    -----------+-CBIO-+-------+----------+-------------+-------------+------------
          Total(Average)       10.54 (1)  24.76 (2.37)  56.50 (5.47)  45.00 (4.71)

Verify列の[Tttt] は各プログラムの結果がすべて等しいことを示しています。 ()内の数字はAZ-Prologのフルコンパイルコードの実行時間を1としたときの倍率です。

### 10-2. AZLINT

AZ-PrologコンパイラでPrologソースのリント（プログラム･チェッカー）をおこなうことができます。従来はazlint.exeという独立したスタンドアローンアプリケーションでしたが、Ver7からはコンパイラオプションに「/lint」をつけることで、コンパイルせずに診断のみをおこなうことにしました。

    C:¥>azpc　-p　/lint ファイル名並び　{/log} ↓

「/log」を付けると、画面と同時に、azpc.logというファイルに診断内容を出力します。 各ファイル、1モジュール毎に次のような情報を得ることができます。
(1)シンタックスエラーのチェック
(2)決定性にコンパイルされる述語の一覧
(3)非決定性にコンパイルされる述語の一覧
(4)インタプリティブコールとなるゴールの一覧
(5)使用している組込述語の一覧
(6)extern宣言群のうち、使用しているものの一覧
(7)組込述語のオーバーライト定義のワーニング
(8)public宣言をしている述語が1つもないときそのワーニング
(9)無視するpublic宣言、無視するコマンド
(10)publicでない述語でモジュール中でも使われていない述語の一覧

ただし、これらの情報は｢コンパイルされた場合にどうなるか｣ですので、インタプリタコード上では非決定であってもコンパイル時には決定性述語という場合もあります。（主にモード宣言に関して発生する点です。ただしインタプリタ上でも厳密にモード宣言どうりに使われていれば、効率上はともかく同じ結果にはなります。）
各情報について順番に説明しながら、azlintを使ったデバッグについても言及しましょう。

##### （1）シン夕ックスエラーのチェック

ファイルにシン夕ックスエラーがあると、その節位置番号（つまりファイル中の何番目に書かれている節か、であって述語の何節めかではありません）とエラーとなった周辺の内容を表示して処理を停止します。
シンタックスエラーは、単純な括弧の対応不良、ピリオドの付け忘れといったレベルからオペレータの定義内容に係わる複雑なものまで多岐にわたりますから、エラー箇所の前後を注意して良く見る必要があります。オペレータやオペレータと同じアトムを使っている場合は、まずオペレータ定義の内容を調べて下さい。大抵は括弧を補ったり、正規の表現にすることで何とかなります。
＜例＞

    test(X):-X= = spy → true.
    = = , spy, →
    がオペレータ定義
    ↓
    test(X):-X = =(spy)→ true.

シンタックスエラーはインタプリタ上で、“echo(_,on).”としてからコンサル卜するか、AzEdit上でコンサル卜することでも判りますが、AZLINTが最も簡便です。

##### （2）決定性にコンパイルされる述語･非決定性にコンパイルされる述語

決定性に書ける処理（述語）は決定性にすべきです。メモリ効率処理効率が違って来るからです。決定性と判定された述語は、他モジュールで使う（他モジュールでextern宣言する）ときにはその情報を付加しておきましょう。（detプレフィックスを付ける）
＜例＞

    : extern det :述語名／アリティ.

決定性にするには、カットオペレータ、モード宣言を積極的に使うことのほかに、externの述語を使うときにその述語が決定性であるかどうかも重要です。
＜例＞

    決定性とならない
    決定性となる

    append([],L,L).
    append([],L,L):-!.

    append([AIL],B,[AIC]):-
    append([AIL],B, [AIC]):-

    append (L,B, C).
    append(L,B,C).

    または左の定義のままで
    :-mode append(+,+,-).を追加する。

決定性になるように記述したつもりでも、非決定性と判定されたときは要注意です。本来のロジック上の誤りである場合以外に、バグが潜んでいる可能性があります。

a) | externの述語を使っており、これが決定性なのにdet:宣言がない、またはextern宣言そのものを忘れ、イシタプリティブcall（組込が非決定述語
b) | ゴールの一部にスペルミスした述語callがあり、インタプリティブcallとなっている。
c) | モード宣言の引数ミス。
d) | ピリオドとカンマをまちがえて次の単位節を最終ゴールと見なしている。 （意外に多いミスです。）

＜例＞

    a:-b,c,←本来はピリオド。
    b.

##### （3）インタプリティブcallとなる述語

本来、動的に「assert」または「consult」して使われる述語以外のものが表示された場合は,前項の中のa)、b)であることは間違いありません。

##### （4）使用組込述語の一覧

一部の組込述語（主に画面制御用）を使っているプログラムは、コンパイルオプションとして「/curses」または「/i」が必要です。 使われている組込述語の一覧を見ることでチェックできます。

##### （5）組込述語のオーバーライト定義のワーニング

インタプリタでは、組込述語と同じファンクタ、アリティを持つ述語のコンサルトはエラーとなりますが、コンパイルすることはできます。 すなわち、低レベルの組込述語を組み上げて上位の組込述語の動作を定義しなおす（putを使ってwriteを最定義、getを使ってreadを最定義する等）ことなどができます。ただし、こうした意図でないのにこのこのワーニングが出たときは、明らかにソースファイル中のミスです。

＜例＞

a:-b, |
|  | c. | ← | ピリオドとカンマの書きまちがい。
|  | write(a). |  |
|  | ↑ |  |
|  | write/1の定義になってしまう。

##### （6）使われていないスタティック述語の一覧

AZ-Prologでは、外部モジュールから呼ぶことの出来る述語は、publicの宣言をするようになっています。
:-public　述語名/アリティ.
:-publicall.（全述語）
とすることで、他モジュールから呼ぶこともできますし、インタプリタからも使うことができます。（組込述語として登録される）。
もう1つ書き方があり、
:-public invisible :述語名/アリティ.
とすると、組込述語の登録は行いません。すなわち、他モジュールで使うことはできますが、必ずそのモジュールではextern宣言を入れなければなりません。
publicでない述語は、モジュール内のみにおいて使うことが出来ます。言い換えると、他の述語のサブ述語となります。
こうした述語を「static述語」と呼びます。static述語は他から見えませんので、同じ述語名、アリティのものが他モジュールにあってもリンクエラーを起こすことがありません。
ただし、同一モジュール中でまったく使われていないstatic述語は外からも呼ばれないので、結局はムダとなります。開発中では良く起きることではありますが、完成したアプリケーションをコンパイルするときには、ファイルから削除するかコメントにしておきましょう。

##### （7）定義述語の一覧

多くの節からなる述語で引数の数のミスをした節が混じっていると、当然のことながら別述語となってしまいます。一覧表を見て同一述語名で引数違いが含まれていれば、意図したものか見なおしましょう。

##### （8）その他のワーニング

前記の説明で十分でしょう。必要に応じて役立てて下さい。

##### （9）その他の使い方

AZ-Prologコンパイラでは、モジュール単位にオブジェクトになり、ファイル中には任意にモジュール宣言を入れることになっています。この時、自己モジュールになく、他モジュール中で定義されている述語を使うときは、extern宣言を入れた方が、直接関数呼び出しとなり、高速化されます。 しかし、実際問題として開発中に複数モジュール中の定義を常にチェックしながら宣言を書いていくのも面倒です。 こんな場合には、「azlintでlogをとり、そのログファイルをエディタに読み込んで、“interpritive call”として出力されている述語名一覧を切り出して、extern宣言に一括変換したものを元のファイルに追加すれば簡単に出来ます。

##### （10）その他

Prologによくあるバグで、「Lint」には反映されないものとして変数名のミススペルがあります。Prologは変数宣言の必要も型指定も不要で、また未束縛変数であっても引数として許されるので、他言語のように、コンパイル時やリントユーティリティではチェックしようがなく、実行時に組込述語でエラーが発生してわかる場合があります。

ANS=3,X is Ans+4, | …… | 〈実行時エラー〉
|  | 〈別変数となるケース〉

次のようなケースではケースをよくながめる以外ないでしょう。

定義 | a(l,one) |  | 実行 | ?-SP=2,a(Sp,X).
| a(2,two) |  |  |

述語情報の中に、頭に数字の付いた定義したおぼえのない述語が含まれていることがありますが、これはLint自身がソースプログラムを読み込む時に、解析しながら、展開／たたみ込みをして生成したものです。
主に節中にOR述語、IFThen、ゴール列を引数とした述語(call、errorsetなど）などの切り出し部分です。
「azlint」は、AZ-Prologコンパイラのソースー次解析部と同一ルーチンを使って記述されています。

### 10-3.システムプログラム

パッケージにはAZ-Prologの機能拡張プログラムが付属しています。
カスタマイズインタプリタの生成、スタンドアローンアプリケーション生成など、必要に応じて作業場所へコピーし、コンパイルしてください。

##### プログラムの格納場所

Windows： | %AZProlog%¥system
Linux： | ${AZProlog}/share/azprolog/system
Mac： | ${AZProlog}/share/azprolog/system

##### 各プログラムの概要

system/ext/ | 拡張ライブラリ(.dll .so .dylib) のソースとMakefileです。 azedit、clp、mecab、oniguruma、redis、websock、socket などのディレクトリごとに分かれています。
system/C/ | C言語で記述された拡張用ソースが格納されています。
system/make/ | インタプリタの再Make参考Makefile,azpc入力ファイルがあります。
system/pl/ | 機能拡張、スタンドアローンアプリケーション用のprologソースです。 これらを使っているユーザのプログラムをコンパイルするときには、該当ソースも合わせてコンパイルリンクしてください。 <システムプログラム>
azserve.pl prologcgi.pl mlt_child.pl mlt_parent.pl setof.pl iso_pred.pl utility.pl odbc_prolog.pl manual.pl | OLEオートメーションサーバのトップレベル述語 CGI用インタプリタ"prologcgi"トップレベル述語 並列処理用子プロセストップレベル述語 並列処理用親プロセス述語 setof,bagof,findall,s_qsort のソース Prologで記述されたISO 18述語 Prolog定義の正規表現などのユーティリティ ODBCをsql風に利用する上位述語 マニュアル表示述語(manual/0,manual/1)のソース
<ユーティリティプログラム>
cgi2bytecgi.pl dump.pl error.pl puttxt.pl count.pl | PrologCGIソースバイトコード変換ツール バイナリファイルの１６進ダンプツール エラーメッセージ変更用ツール CGIソースをブラウザに出力するプログラム Prologプログラムの節行数カウントツール

##### ユーティリティプログラムの使い方の例としてcount.pl を動かしてみましょう。

コンパイル：

    > azpc -p /e count /no count.pl

スタンドアローン実行形式プログラム「 count 」が生成されます。

     C:¥>count -p        ファイル名並び↓

と入力することにより、各ファイルのライン数・節の数・述語数が表示され、最後に全ファイルのライン・節・述語の合計が表示されます。出力をファイルに落としたければ、リダイレクトを使って次のようにしてください。

     C:¥>count -p　queen.pl setof.pl>outfile↓

Prologの場合、1行中にゴールを並べて書くことがあり、またコメントや空白行を入れて、見易くすることがありますので、エディタ上のライン数がそのままプログラムの大きさにはなりません。
本ユーティリティでは、プログラムだけを扱いますので、ソースの管理に役立つと思います。尚、ライン数のカウントは、頭部は1ライン、ボディ部の各ゴールも各1ラインとし、ORゴール、callゴールなど、ゴールを引数とするゴールは更にそのゴール数を加えています。
その他の用途として、述語に含まれる節数が、どうであるか、また一節に平均して何ライン含まれるかなどの調査にも応用できます。

### 10-4.サンプルプログラム

パッケージにはAZ-Prologの各機能ごとのサンプルプログラムが付属しています。
ディレクトリごと作業場所へコピーしてLinuxではコンパイルしてください。

##### プログラムの格納場所

Windows： | %AZProlog%¥sample
Linux： | ${AZProlog}/share/azprolog/sample
Mac： | ${AZProlog}/share/azprolog/sample

各ディレクトリでコンパイルして実行させるものは、ソースファイルとともにコンパイラの使い方の参考になるようにMakefileが含まれています。また、各ソースファイルには使い方などのコメントが書かれていますのでお読みください。

##### 各サンプルプログラムの概要

sample/cgi_demo | CGIのデモが格納されています。 環境設定の詳細は、HowToInstall.txtに書かれています。
sample/C_InterfaceSample | C言語で述語を記述するサンプルソース格納されています。
sample/HDP | 分散したPrologプログラムをパイプ連結して結果を求めるサンプルです。 実行バッチ(queentest.bat、queentest.sh)で起動します。 コンパイルMakefileが含まれています。
sample/LargeCapacityMemory | 大容量のメモリ空間を使うテストプログラムが格納されています。
sample/ext | 動的リンクされるようにコンパイルされた拡張ライブラリを使用するサンプルです。 現在は、mecab、redis、websockの三種類です。
sample/neuralnet | バックプロパゲーションニューラルネット述語を使ったサンプルプログラムです。 ソースファイル（font.pl)をお読みください。
sample/oleauto | Windowsのみの機能です。OLEオートメーション機能のサンプルプログラムです。 readole.txt に詳細が書かれています。
sample/parallel | 並列処理のサンプルプログラムが格納されています。 １）AZ-Prologインタプリタに、parallel_test.plをコンサルトし、|?-test. で全実行します。 ２）pentomino.exe を起動し、|?-menu. で実行し、複数の方法でペントミノパズルを解きます。 コンパイルバッチ（make_pen.bat)が含まれています。
sample/clp | 制約論理のサンプルプログラムです。 起動方法などの詳細はファイルに書かれています。 AZ-Prolog.V1から附属している。アプリケーションサンプルです。 使用方法は各ソースに書かれています。
magic.pl sendmore.pl sudoku.pl | 魔方陣を解くプログラムです。 覆面演算の例題です。 数独を解くプログラムです。
sample/other | AZ-Prolog.V1から附属している。アプリ使用方法は各ソースに書かれています。
trans.pl formula.pl del_app.pl s_utility.pl queen.pl azlisp.pl | 簡単な日英翻訳プログラム 式の展開プログラム(Written by Kaba) appendを含むリスト処理を差分リストへ変換するプログラム リスト処理例題 マニュアルで説明しているN-Queenのプログラムです Prologで書かれたLispインタプリタ

##### サンプルプログラムの使い方の例としてazlisp.pl を動かしてみましょう。

###### 起動方法

    > prolog
    ?- [-'azlisp.pl'].
    ?-lisp(con).↓

でRead-Eval-Printループに入ります。
S式評価はlisp_Eval（X，V）で、XにPrologのリスト形式で評価するS式を与えるとVにその評価した値が返されます。

###### LISP言語仕様

*シンタックス
キャラクタコード:32以下の文字は空白文字として扱われます。
「'(シングルクォート)」と「()」、空白」文字以外の文字はアトムを構成する通常の文字となります。大文字、文字の区別はあります。
数字のみからなるアトムは整数となります。

*特殊型式は以下のものがあります。
（quote x）：x自身を返す
（progn forml…formn）：form1，‥‥，formnを順に評価、formnを評価した値を返す。
（cond clause1‥‥clausen）：clause1，‥‥，clausenの第１要素を順に評価する。
最初に「 nil 」以外のものを返した「 clause 」について、第２要素以外を「prognに与えられたように評価し、その値を返す。但し、clauseでただ１つの要素しかもたないときは、その返した値自体を返す。 それ以降の「 clause 」の第１要素の評価はおこらない。 （de function-name argumet-list・body） function-nameが（lambda argument-list・body）の大域的な名前として登録される。

*特殊型式以外のものは関数呼出しとして扱われる。従って、その引数がまず順に評価され、結果のリストに関数がupplyされます。
組込関数として以下のものがあります。

・基本５関数：car，cdr，cons，eq，atom
・(print x)：xを出力する。値はx自体．
・(+xy),(-xy）：それぞれx＋y，x-yを返す。
・(read)：入力したS式を返す。
・(terpri):改行の出力。値はt.
・(help):組込関数,特殊型式名,現在定義されている関数名を出力する。値はt.
・(bye):Read-Eval-Printループを抜ける。
・(gefdef fname):fnameの関数定義をラムダ式の形で返す。
・(load file)(save file):現在の関数定義をファイルにロード/セーブする。

＜例＞

    (de append(x y)
    (cond((eq x nil) y)
    (t (cons(car x)(append (cdr x) y)))))
    → append
    (append '(1 2 3) '(4 5))
    →(1 2 3 4 5)

### 10-5.システムインプリメンテーション

##### （1）スタック

AZ-Prologの実行制御には次のスタックが使われます。

###### グローバルスタック

グローバル変数、及びReadされた項、ユニブ（=../xfy）等で内部的に作られる構造体が積まれるスタックです。

###### ローカルスタック

Prolgの実行をコントロールする制御フレーム、及びローカル変数、組込述語の引数バッファに使われるスタックです。

###### トレイルスタック

ユニファイされた変数の情報を記録し、バックトラック時に元へ戻すために使われるスタックです。
尚、本システムはC言語でインプリメントされており、これ以外にマシンスタック（C言語レベルで使用されるスタック）があります。
グローバルスタック･ローカルスタック、トレイルスタックのサイズは、AZ-Prologコンパイラによって再構成されたインタプリタ、または単独実行モジュールを生成するときに指定するようになっています。

##### （2）Successful pop　と　Last call Optimization

AZ-Prologでは、スタックの使用量を減らため「 Successful pop 」と「 Last call Optimization 」を行なっています。

###### Successful pop

ある述語が決定性の終了をしたとき（この述語の実行に｢オルタナティブ（他の可能性）がない｣という意味です）この節の実行に使われた制御フレーム、ローカル変数部分をローカルスタックから取り除く事を“successful pop”といいます。
このため、組込述語を含む述語の実行が決定的に終了することによって、このゴールは再充足されなくなります（例えそれ以後にそのゴールに新しい可能性が出来たとしても、その新しい可能性は試されない）ので、次のような注意が必要です。

a(1). b:-a(X),write(X),assertz(a(2)),fail.
| ① |  | ② |
| ?-b 1 no

ゴール①の実行は、定義節「 a/1 」が一つしかありませんので決定性の終了をし、このゴールに対応する制御フレームをローカルスタックから取り除きます。
このあとで、ゴール②により、「 a/1 」の代替節を「 assert 」してから、「 fail/0 」によりバックトラックしても、①が再充足されることなく、「 b/0 」の実行が失敗します。
非決定性の組込述語も、決定性終了をした場合は同様です。

a(1). b:-retract(a(X)),write(X),Y is X+1,assertz(a(Y)),fail)
| ① |  | ② |
?-h 1 no

「 retract/1 」は、引数に指定された削除を試みるべき節がヒープ領域に残っている間は非決定性の終了をし、制御フレームが残っていますが、この場合のように一つだけ定義されている節を削除した後では、決定性の終了になります。

###### Last call optimization

Prologにおいて、再帰はもっとも基本的なプログラミング技法の一つです。
次の例を見て下さい

write_n(0) :-!. write_n(X) :-write(X),put(32),Y is X-1,write n(Y).
|  | ① |
|?-write_n(10). 10 9 8 7 6 5 4 3 2 1 yes

「 write_n/1 」は引数の値を出力し、1つずつ減じながら再帰し、引数の値が0になることによって停止します。
「 write_n/1 」の第2節の最後のゴールを実行するとき、この節自体と、それまでの各ゴールにオルタナティブ（他の可能性）がない状態になっています。すなわち、この最後のゴール①が失敗したとしても、この節には、代替節も、各ゴールの再充足もないわけですから、この節自体に要したフレームを残さなくても良いことになります。
このようなフレームを削除することを“Last call optimization”といいます。
この制御は、特に自分自身に再帰している場合（Tail recursion）ばかりでなくともおこなわれます。
また、カットオペレータが使用されることにより節の代替節、再充足すへきゴールがカットされた場合も同様な最適化を行ないます。
リストの結合を行なうプログラム「 append/3 」において次の3つの書き方が可能ですが、①よりも②、③の方がスタックの消費が少なくて済みます。

① | append([A|B],C,[A|BC]):-append(B,C,BC). append([],L,L).
② | append([],L,L). append([A|B],C,[A|BC]):-append(B,C,BC).
③ | append([A|B],C,[A|BC]):-!,append(B,C,BC). append([],L,L).

このようにLast callを効果的に生かすと、スタックの使用を押え、実行も早いプログラムにすることができます。 前掲の「 write_n/1 」はローカルスタックが全く延びずに実行することができます。

##### （3）ガベージコレクション

AZ-Prologは、ヒープ領域･アトム領域･グローバルスタックのガベジコレクション（ちり集め:GC）がそれぞれの領域が不足した場合に起動されます。
グローバルスタックは、バックトラック時に解放されますが、前掲の「 write_n/1 」のようにバックトラックを起こさずに実行するものに関しては、この節の中に現れたグローバル変数が解放されません。（変数Ⅹがグローバル変数の扱いとなる）
その結果、グローバル変数領域が不足した時に、必要な変数セルとそうでない変数セルを区分けし、前者のみを回収する処理（グローバルGC）がおこなわれます。
この機構のために「 write_n/1 」は、引数がいくら大きい数値であっても、スタックオーバーフローを起こさずに動くことができるのです。
尚、プログラム全体の流れの中で、部分的にバックトラックを引き起こすことで、グローバルスタックの解放を計画的に行ない、グローバルGCの発生をおこえることができます。

write_n1(X) :- write_n(X),fail.
|  | ① |
write_n1(_).

「 write_n/1 」の中でグローバルスタックを多量に使用した後、「 fail/0 」で解放し、GCが発生する前に解放することができます。（ただし、①の中でGCが発生しないという事を前提とします）

### 10-6.エラー・メッセージ一覧

1 | Syntax error | 構文エラー。
2 | Can't see the file | 指定されたファイルをリードオープンできない。
3 | Can't tell the file | 指定されたファイルをライトオープンできない。
4 | End of file encountered | ファイルエンドを越えてリードしようとした。
5 | Illegal file name | ファイル名が正しく指定されていない。
6 | Too many variables | 節または項中の変数が多すぎる。
7 | Too complex term | 項が複雑すぎる。
8 | builtin or C pred exist | 組込述語が既に存在しているのにそれと同じ述語名・アリティを持つユーザ述語あるいはシステム述語を定義しようとした。
9 | Illegal argument supplied | 組込述語に対して正しくない引き数が与えられた。
10 | Illegal Goal | 整数あるいは未代入変数をゴールとして実行しようとした。
11 | Illegal clause | 節として認められない。
12 | Illegal define tag | システムエラー。
13 | Illegal throw tag | throw述語の引数のタグ指定が不正だった。
14 | Illegal catch tag | catch述語の引数のタグ指定が不正だった。
15 | unknown predicate call | unknown(_,error)を実行後定義されてないゴールを実行しようとした。
16 | Heap area exausted | ヒープ領域（プログラムを入れておく領域）がオーバーフローした。
17 | Trail stack overflow | トレールスタックがオーバーフローした。
18 | Global stack overflow | グローバルスタックがオーバーフローした。
19 | Local stack overflow | ローカルスタックがオーバーフローした。
20 | Malloc failed | メモリアロケーションが出来ない。
21 | No more break | ブレークレベルが深くなりすぎてこれ以上ブレーク出来ない。
22 | Division by 0 | 0による除算を実行しようとした。
23 | Too complex arithmetic | 数式が複雑すぎて評価出来ない。
24 | Overflow | フロート演算の結果が大きすぎる。
25 | Underflow | フロート演算の結果が小さすぎる。
26 | Illegal Arithmetic | 値のセットされていない変数などが入った式を評価しようとした。
27 | Illegal character code | 漢字コードにないキャラクタコードを指定した。
28 | Edit buffer no space | エディタバッファがオーバーフローした。
29 | Kill buffer no space | キルバッファがオーバーフローした。
30 | out of buffer | e_jump/1 でバッファ内にない位置を指定した。
31 | ^Gerror | CTRL-G がコンソールから入力された。
32 | Search string is too long | 検索しようとした文字列が長すぎる。
200 | user errors limit | error/1 でユーザエラーの限界を越えた。
225 | abort | abort/0 を実行するとこのエラーが発生した事になり errorset/2 で受け止める事が出来る。

### 10-7.エデイタ（AzEdit）コマンドー覧

カーソルの移動
CTRL-F | カーソルを一文字前に移動 | (Forward character)
CTRL-B | カーソルを一文字後ろに移動 | (Backward character)
CTRL-N | カーソルを一行下に移動 | (Next line)
CTRL-P | カーソルを一行上に移動 | (Previous line)
ESC-F | カーソルを現在の単語の次に移動 | (Forward word)
ESC-B | カーソルを一つ前の単語の先頭に移動 | (Backward word)
CTRL-A | カーソルを行の先頭に移動 |
CTRL-E | カーソルを行の最後に移動 |
CTRL-V | 次の画面を表示 |
CTRL-Z | 前の画面を表示 | (End of line)
ESC-< | カーソルをテキストの先頭に移動 | (View the next screen)
ESC-> | カーソルをテキストの最後に移動 |
CTRL-X CTRL -X | カーソルとマークの交換 | (Exchange)
ESC-Space | カーソルの位置にマークを付ける |
挿入と削除
Return | NLをカーソルの前に挿入 |
CTRL-O | NLをカーソル位置に挿入 | (Open line)
Tab | タブをカーソルの前に挿入 |
CTRL-Q | 特殊文字の挿入 | (Quoted insert)
CTRL-D | カーソル位置の文字を削除 | (Delete character)
BS,CTRL -H | カーソルの前の文字を削除 | (Back Space)
ESC-D | カーソルのある単語を削除 | (Delete word)
ESC-BS | カーソルの一つ前の単語を削除 |
CTRL-K | カーソルより右を削除 | (Kill line)
CTRL-W | カーソルとマークの間を削除 | (Kill region)
CTRL-Y | ESC-D,CTRL-K,CTRL-Wで削除したテキストをカーソルの前に挿入 | (Yank)
探索と置換
CTRL-S文字列ESC | 前向きの探索 | (Search)
CTRL-R文字列ESC | 後ろ向きの探索 | (Reverse search)
CTRL-S CTRL-S | 同じ文字列の前向き探索 |
CTRL_RCTRL-R | 同じ文字列の後ろ向き探索 |
ESC_R 文字列1ESC 文字列2ESC | 文字列1を文字列2に置き換える | (Replace)
ESC-Q 文字列1ESC 文字列2ESC | 文字列1を文字列2にキーボードからの指示に従い置き換える | (Query replace)
ファイル操作
CTRL-X CTRL-V ファイル名 | ファイルをバッファに読み込む | (Visit file)
CTRL-X CTRL-I ファイル名 | ファイルをバッファに読み込む | (Insert file)
CTRL-X CTRL-W ファイル名 | テキストをファイルに書き出す | (Write file)
プログラム領域への転送
CTRL-X CTRL-S | テキスト全体のreconsult |
CTRL-XS | 領域のreconsult |
バッファの領域確保･切替･切り離し
CTRL-C | バッファの切替 |
CTRL-X CTRL-B | バッファの切替 |
CTRL-X CTRL-C | バッファを切り離し（領域開放） |
AzEditの終了
CTRL-X CTRL-Z | PROLOGへ戻る |
CTRL-XZ | 画面の下の部分にスクロール領域を設定してPROLOGへ戻る |
その他のコマンド
CTRL-L | カーソルを中心に画面を再配置 |
ESC-+ | AzEditの使用する行数を一行増やす |
ESC— | AzEditの使用する行数を一行減らす |
ESC-W | AzEditの使用する行数を最大にする |
ESC-U | 単語を大文字に変換 | (Upper case)
ESC-L | 単語を小文字に変換 | (Lower case)
ESC-C | 単語を先頭だけ大文字に変換 | (Capitalize)

### 10-8.コンソール　ヒストリ、テンプレートコマンド一覧

ヒストリー
CTRL-X | ヒストリーの表示
テンプレート
CTRL-F | 現在の行にテンプレートから1文字コピーする
CTRL-A | 現在の行にテンプレートに残っている全ての文字をコピーする
CTRL-E | テンプレート内の1文字をスキップする
CTRL-W | 挿入モードに入る。もう1度押すと挿入モードを解除する
CTRL-T | 現在の行の内容をテンプレートにコピーする
CTRL-Q | 現在行の先頭まで戻り最初の2文字をスキップする
CTRL-U | 現在のテンプレートより一つ古いヒストリーをテンプレートにコピーし同時に現在行の最初からコピーする(CTRL-A) （最初のCTRL-UはCTRL-Aと同じ）
CTRL-N | 現在のテンプレートより一つ新しいヒストリーをテンプレート にコピーし同時に現在行の最初からコピーする(CTRL-A)

### 10-9.ISO対応一覧

No. | ISO述語 | AZ-Prolog 対応
1 | !/0 | ○
2 | **/2 | ○
3 | */2 | ○
4 | +/2 | ○
5 | ,/2 | ○
6 | -/1 | ○
7 | -/2 | ○
8 | (//)/2 | ○
9 | (/)/2 | ○
10 | ;/2 | ○
11 | </2 | ○
12 | <</2 | ○
13 | =/2 | ○
14 | =:=/2 | ○
15 | = | ○
16 | ==/2 | ○
17 | ==/2 | ○
18 | >/2 | ○
19 | >=/2 | ○
20 | >>/2 | ○
21 | @<2 | ○
22 | @= | ○
23 | @>/2 | ○
24 | @>=/2 | ○
25 | +/1 | ○
26 | (/)/2 | ○
27 | /1 | ○
28 | =/2 | ○
29 | ==/2 | ○
30 | truncate | ○
31 | log | ○
32 | abolish/1 | ○
33 | abs/1 | ○
34 | arg/3 | ○
35 | assert/1 | ○
36 | assert/2 | ○
37 | asserta/1 | ○
38 | assertz/1 | ○
39 | atan/1 | ○
40 | atan2/2 |
41 | at_end_of_stream/0 |
42 | at_end_of_stream/1 |
43 | atom/1 | ○
44 | atom_chars/2 | ○
45 | atom_codes/2 | ○
46 | atom_concat/3 | ○
47 | atomic/1 | ○
48 | atom_length/2 | ○
49 | bagof/3 | ○
50 | call/1 | ○
51 | catch/3 |
52 | ceiling/1 | ○
53 | char_code/2 | ○
54 | char_conversion/2 | ○
55 | clause/2 | ○
56 | close/1 | ○
57 | close/2 |
58 | compound/1 | ○
59 | copy_term/2 | ○
60 | cos/1 | ○
61 | current_char_conversion/2 | ○
62 | current_input/1 |
63 | current_op/3 | ○
64 | current_output/1 |
65 | current_predicate/1 | ○
66 | current_prolog_flag/2 | ○
67 | discontiguous/1 |
68 | dynamic/1 | ○
69 | ensure_loaded/1 | ○
70 | exp/1 | ○
71 | fail/0 | ○
72 | findall/3 | ○
73 | float/1 | ○
74 | float_fractional_part/1 | ○
75 | float_integer_part/1 | ○
76 | floor/1 | ○
77 | flush_output/0 | ○
78 | flush_output/1 |
79 | functor/3 | ○
80 | get_byte/1 |
81 | get_byte/2 |
82 | get_char/1 | ○
83 | get_char/2 | ○
84 | get_code/1 | ○
85 | get_code/2 | ○
86 | halt/0 | ○
87 | halt/1 | ○
88 | include/1 |
89 | nitialization/1 |
90 | integer/1 | ○
91 | is/2 | ○
92 | mod/2 | ○
93 | multifile/1 |
94 | nl/0 | ○
95 | nl/1 | ○
96 | nonvar/1 | ○
97 | number/1 | ○
98 | number_chars/2 | ○
99 | number_codes/2 | ○
100 | once/1 | ○
101 | op/3 | ○
102 | open/3 | ○
103 | open/4 |
104 | peek_byte/1 |
105 | peek_byte/2 |
106 | peek_char/1 |
107 | peek_char/2 |
108 | peek_code/1 |
109 | peek_code/2 |
110 | put_byte/1 |
111 | put_byte/2 |
112 | put_char/1 | ○
113 | put_char/2 | ○
114 | put_code/1 | ○
115 | put_code/2 | ○
116 | read/1 | ○
117 | read/2 | ○
118 | read_term/2 |
119 | read_term/3 |
120 | rem/2 | ○
121 | repeat/0 | ○
122 | retract/1 | ○
123 | round/1 | ○
124 | set_input/1 |
125 | setof/3 | ○
126 | set_output/1 |
127 | set_prolog_flag/2 | ○
128 | set_stream_position/2 |
129 | sign/1 | ○
130 | sin/1 | ○
131 | sqrt/1 | ○
132 | stream_property/2 |
133 | sub_atom/5 | ○
134 | throw/1 | ○
135 | true/0 | ○
136 | unify_with_occurs_check/2 |
137 | var/1 | ○
138 | write/1 | ○
139 | write/2 | ○
140 | write_canonical/1 | ○
141 | write_canonical/2 | ○
142 | writeq/1 | ○
143 | writeq/2 | ○
144 | write_term/2 |
145 | write_term/3 |

«ご注意»
(１)本サイトの内容の一部を転載する場合は「AZ-Prologのマニュアルサイトからの転載」とご明示ください。
(２)本サイトの内容について予告なしに変更することがあります。
(３)本サイトの内容につきましては、万全を期して作成致しておりますが、万一誤り、お気付きの点がございましたら、ご連絡下さいますようお願い致します。
(４)運用した結果の影響につきましては、（3）にかかわらず責任を負いかねますのでご了承下さい。
▲