kprolog K-Prolog Compiler Version 6.0

プログラムのデバッグ

実際にPrologプログラムを作って動作させるためには、 デバッグという作業が必要になります。K-Prolog には、 ユーザがデバッグする時に助けになるいくつかの機能を組込んでいます。
未定義の述語の検出
set_prolog_flag/2 組込み述語での指定によって、 未定義述語を実行しようとしたときの動作を指示できます。
エラー表示
組込み述語でのエラー検出時に、エラーの原因を表示たり、 catch/3組込み述語により あらかじめ指定した述語に制御を渡すこともできます。
debug
トレーサやステッパを含むデバッガです。
ここではデバッガとして独立の機能となっている debug について解説します。
debug組込み述語を実行すると、デバッグ状態に入ります。 この状態では実行するゴールのトレース表示や、 スパイ点の設定、実行中のゴールの制御などができます。

デバッガは、デバッグの対象となる述語を次の4点で制御します。

call
述語が呼び出された時点
exit
述語の1つの節の本体の実行が成功した時点
redo
述語の exit の後に後戻りにより戻ってきた時点
fail
述語が最終的に失敗した時点
これら4つの点をポートといいます。 デバッガではこれら4ポートにおいて節の頭部を表示し、あるいは、 各種の制御コマンドを実行することができます。 プログラムをデバッグする場合は、call、exitポートでのゴールの 引き数を調べたり、予期しない失敗を捕捉するためにデバッガを使用します。 残念ながらコンパイルコードの性能を維持するために、 コンパイルされた述語及び外部述語と一部の組込み述語については callポートでのトレースしか表示できません。

引き数を調べるためには、creep、skip、や warpを使って そのゴールの callポートや exitポートに向かって実行を進めます。 また、spy点を設定したうえで leap によって指定の述語が呼び出される ところまで進めることもできます。
失敗を捕捉するためには、

   leash(off),leash(+fail)
で failポートで止まるように指定すればよいでしょう。また、
   leash(off)
を指定すれば、ポートにおいて止まらずに実行トレースを得られます。 以下にデバッガをコントロールするための組込み述語を紹介します。


debug
デバッグ状態に入ります。
nodebug
デバッグ状態を終わります。
trace
トレースを行うことを指定します(トレースとは、 ポートにおけるレベルと頭部の表示を意味します)。
notrace
トレースを行わないことを指定します(スパイ点は有効です)。
leash(Mode)
ポートにおける制御コマンドの受け付け状態を変えます。 コマンドを受け付けるポートを活性ポートといいます。 Modeには、次のものが指定できます。
full
すべてのポートを活性化します。
tight
call、redo、failポートを活性ポートにします。
half
call、redoポートを活性ポートとします(既定値)。
loose
callポートを活性ポートとします。
off
すべてのポートを非活性化します。
+Port
指定ポートを活性化します (Portはcall、redo、exit、failです)。
-Port
指定ポートを非活性化します。
spy(P),spy(Name/Arity)
述語の節の頭部P、または名前NameとアリティArityを指定して、 スパイ点を設定します。 スパイ点のある述語のポートはすべて活性化されます。
nospy(P),nospy(Name/Arity)
スパイ点を消去します。
nospy
すべてのスパイ点を消去します。
unknown(Spec)
Specは、break,failのいずれかを指定します。 プログラムの実行中に定義していない述語を 実行しようとしたときの動作として、 指定します。
debugging
デバッガの状態を表示します。

デバッグ中のプログラムが活性ポートに達したとき、 プロンプトに対して以下の1字から成る制御コマンドを入力して、 デバッガの実行を制御します。


c(creep),<nl>
次の活性ポートまでトレース表示付きで実行を進めます。
l(leap)
次のスパイ点までトレース表示なしで実行を進めます。
s(skip),w(warp)
callまたはredoポートで可能で、 対応するexitまたはfailポートまでトレース表示なしで実行を進めます。 exitまたはfailポートは一時的に活性化され、 制御コマンドを受け付けます(途中のスパイ点は無視します)。
q(quasi_skip)
skipとほぼ同様ですが、スパイ点は有効です。
r(retry)
すべてのポートで可能で、対応するcallポートに制御を移します。
u(upper)
一つ上のレベルの述語のポートまで実行を進めます。
;(redo)
exitポートのみで可能で、後戻りを起こしてredo ポートに制御を移します。
f(fail)
call、exit、またはredoポートで可能で、 その述語を最終的に失敗させ、failポートに制御を移します。
p(print ansestor clause)
親ゴールを節の形式で表示します。
P(print ansestor clauses)
すべての親ゴールを節の形式で表示します。
g(ansestor goal)
親ゴールを表示します。
G(ansestor goals)
すべての親ゴールを表示します。
?
leash(full) を行ないます。
-
そのポートをleashモードから外します。
b(break)
breakします。再開したときには、再び制御コマンドを受け付けます。
a(abort)
abortします。
n(nodebug)
nodebug述語と同じです。
h(help)
制御コマンドの一覧表を表示します。

debugの実行例


42: ?- debug.
0 exit : call(debug)

yes
43: ?- -qsort.pl.
qsort.pl      43646 words free.

yes
44: ?- listing.
qsort([X|L],W,Result) :-
   partition(L,X,Small,Big),
   qsort(Small,W,R),
   qsort(Big,[X|R],Result).
qsort([],R,R).

partition([X|L],Y,[X|L1],L2) :-
   X@=<Y,
   !,
   partition(L,Y,L1,L2).
partition([X|L],Y,L1,[X|L2]) :- 
   !,
   partitlon(L,Y,L2,L1).
partition([],_,[],[]).


yes
45: ?- qsort([efl,awk,c,lex],[],Progs).
 1 call : qsort([efl,awk,c,lex],[],_148) ? <nl>
  2 call : partition([awk,c,lex],efl,_280,_278) ? b

[BREAK] 46: ?- spy partition.
spy on:  partition/4
yes
[BREAK] 47: ?- ^D
  2 call : partition([awk,c,lex],efl,_280,_278) ? l
   3 call : partition([c,lex],efl,_268,_296) ? l
    4 call : partition([lex],efl,_286,_314) ? l
Error signalled by partitlon([],efl,_304,_286)
Undefined predicate call - predicate not found
trace back(y/n)? y
6 partitlon([],efl,_,_) ? P
5 partition([lex],efl,L1,[lex|L2]) :-
      !,
  --> partitlon([],efl,L2,L1).
4 partition([c,lex],efl,[c|L1],[lex|L2]) :-
      c@=<efl,
      !,
  --> partition([lex],efl,L1,[lex|L2]).
3 partition([awk,c,lex],efl,[awk,c|L1],[lex|L2]) :-
      awk@=<efl,
      !,
  --> partition([c,lex],efl,[c|L1],[lex|L2]).
2 qsort([efl,awk,c,lex],[],Result) :-
  --> partition([awk,c,lex],efl,[awk,c|L1],[lex|L2]),
      qsort([lex|L2],[],R),
      qsort([awk,c|L1],[efl|R],Result).
1 call(qsort([efl,awk,c,lex],[],Result))

Abort

partitolonというスペルミスがわかったのでエディタで修正します。

47: ?- edit qsort.pl.
qsort.pl      43642 words free.

yes

次のように修正しました。

partition([X|L],Y,[X|L1],L2) :-
   X@=<Y,
   !,
   partition(L,Y,L1,L2).
partition([X|L],Y,L1,[X|L2]) :- 
   !,
   partition(L,Y,L2,L1). /* <-- */
partition([],_,[],[]).

もう一度初めから実行してみます。

48: ?- history.
47: <edit [qsort|pl]>
46: <spy partition> 
45: <qsort([efl,awk,c,lex],[],Progs)> ;
49: qsort([efl,awk,c,lex],[],Progs)
 1 call : qsort([efl,awk,c,lex],[],_148) ? w
 1 exit : qsort([efl,awk,c,lex],[],[lex,efl,c,awk]) ? <nl>

Progs = [lex,efl,c,awk] <nl>

yes

答えは出ましたが、ソートの順序が反対です。

49: ?- ;qsort.
49: qsort([efl,awk,c,lex],[],Progs)
 1 call : qsort([efl,awk,c,lex],[],_270) ? <nl>
  2 call : partition([awk,c,lex],efl,_634,_632) ? <nl>
   3 call : awk@=<efl ? b

[BREAK] 50: ?- spy qsort.
spy on:  qsort/3
yes
[BREAK] 51: ?- ^D
   3 call : awk@=<efl ? l
  2 call : qsort([awk,c],[],_696) ? l
   3 call : qsort([],[],_734) ? l
   3 call : qsort([c],[awk],_760) ? l
    4 call : qsort([],[awk],_772) ? P
3 qsort([c],[awk],Result) :-
      partition([],c,[],[]),
  --> qsort([],[awk],R),
      qsort([],[c|R],Result).
2 qsort([awk,c],[],Result) :-
      partition([c],awk,[],[c]),
      qsort([],[],[]),
  --> qsort([c],[awk],Result).
1 qsort([efl,awk,c,lex],[],Result) :-
      partition([awk,c,lex],efl,[awk,c],[lex]),
  --> qsort([awk,c],[],R),
      qsort([lex],[efl|R],Result).
    4 call : qsort([],[awk],_772) ? n

Progs = [lex,efl,c,awk] <nl>

qsortがおかしいようです。

50: ?- listing qsort.
qsort([X|L],W,Result) :-
   partition(L,X,Small,Big),
   qsort(Small,W,R),
   qsort(Big,[X|R],Result).
qsort([],R,R).

yes

エディタで修正します。

51: ?- edit qsort.pl.
qsort.pl      43640 words free.

yes
52: ?- listing qsort.
qsort([X|L],W,Result) :-
   partition(L,X,Small,Big),
   qsort(Big,W,R),
   qsort(Small,[X|R],Result).
qsort([],R,R).

yes
53: ?- ;49.
53: qsort([efl,awk,c,lex],[],Progs)
 1 call : qsort([efl,awk,c,lex],[],_228) ? n

Progs = [awk,c,efl,lex] <nl>

正しく動作することが確認できました。


目次に戻る