[Next]コールバック [Previous]結果の処理 [Up]PoPの使用方法 [Top]

トレース

指定した述語の呼出しをトレースすることができます.
トレースの対象になるのは,トレース・マスクにマッチするトレース・キーを持った述語です.

トレース・キーの設定

トレース・キーは,述語名単位に設定します.
設定するには,述語名predと,トレース・キーtrckey(文字列)を指定してspyメソッドを呼び出します.
pop.spy(pred, trckey)
トレース・キーを省略した場合は,述語名がトレース・キーになります.

トレース・マスクの設定

トレース・マスクは,PoPインスタンス単位に設定します.
設定するには,トレース・マスクtrcmask(正則表現文字列)を指定してtraceメソッドを呼び出します.
pop.trace(trcmask)
トレース・マスクを省略した場合は,'.*' が仮定されますので,トレース・キーを設定したすべての述語がトレースの対象になります.

例えば,すべての使用者定義述語をトレースする設定は,次のようにすればできます.

for p in pop.userdefs():
  pop.spy(p)
  pop.trace()

照会,解除

トレース・キー,トレース・マスクの照会は,それぞれ
pop.spies()
pop.trace_mask()
トレース・キー,トレース・マスクの解除は,それぞれ
pop.nospy(pred)
pop.notrace()
を使用します. 詳細はリファレンスを参照してください.

トレース結果をappendを例に説明します(説明のため,行頭に行番号を付けています).
 1: from PoP import *
 2: pop = PoP()
 3: Append = Atom('append')
 4: a = Variable('a')
 5: x = Variable('x')
 6: y = Variable('y')
 7: z = Variable('z')
 8: pop.assertz(Append([], x, x))
 9: pop.assertz(Append(List(a, tail=x), y, List(a, tail=z)),
10:   Append(x, y, z))
11: pop.spy('append')
12: pop.trace()
13: r = pop.inquire(Append(x, y, [1,2,3]))
14: while r <> None:
15:   print r
16:   r = pop.inquire_next()
このプログラムは,appendを逆に使って,リスト[1,2,3]のすべての分割を求めるものです.
3〜7行目は,必要なアトムや変数を宣言しています.
8〜10行目は,プログラムを登録しています.
11行目でappendに対してトレース・キーを,12行目でトレース・マスクを設定しています.
引数が省略されていますが,結局appendについてトレースが設定されました.
13〜16行目で,プログラムを起動し,すべての解を求めています.

この結果,つぎのようにトレースが出力されます(これにも行番号を付けています).

 1:  [spy] C<0,0> append(_x#8ccb20, _y#8ccd70, [1, 2, 3])
 2:  [spy] >> append([], _x, _x) --> append([], [1, 2, 3], [1, 2, 3])
 3: {'x': [], 'y': [1, 2, 3]}
 4:  [spy] R<0,1> append(_x#8ccb20, _y#8ccd70, [1, 2, 3])
 5:  [spy] => append([_a | _x], _y, [_a | _z]) -->
      append([1 |  _x#8d2bb0],_y#8d2be0, [1, 2, 3]) :- append(_x#8d2bb0, _y#8d2be0, [2, 3])
 6:  [spy] C<1,0> append(_x#8d2bb0, _y#8d2be0, [2, 3])
 7:  [spy] >> append([], _x, _x) --> append([], [2, 3], [2, 3])
 8: {'x': [1], 'y': [2, 3]}
 9:  [spy] R<1,1> append(_x#8d2bb0, _y#8d2be0, [2, 3])
10:  [spy] => append([_a | _x], _y, [_a | _z]) -->
      append([2 |  _x#8d3cb0],_y#8d3ce0, [2, 3]) :- append(_x#8d3cb0, _y#8d3ce0, [3])
11:  [spy] C<2,0> append(_x#8d3cb0, _y#8d3ce0, [3])
12:  [spy] >> append([], _x, _x) --> append([], [3], [3])
13: {'x': [1, 2], 'y': [3]}
14:  [spy] R<2,1> append(_x#8d3cb0, _y#8d3ce0, [3])
15:  [spy] => append([_a | _x], _y, [_a | _z]) -->
      append([3 |  _x#8d4dd0],_y#8d4e60, [3]) :- append(_x#8d4dd0, _y#8d4e60, [])
16:  [spy] C<3,0> append(_x#8d4dd0, _y#8d4e60, [])
17:  [spy] >> append([], _x, _x) --> append([], [], [])
18: {'x': [1, 2, 3], 'y': []}
19:  [spy] R<3,1> append(_x#8d4dd0, _y#8d4e60, [])
20:  [spy] << FAIL
21:  [spy] R<2,2> append(_x#8d3cb0, _y#8d3ce0, [3])
22:  [spy] << FAIL
23:  [spy] R<1,2> append(_x#8d2bb0, _y#8d2be0, [2, 3])
24:  [spy] << FAIL
25:  [spy] R<0,2> append(_x#8ccb20, _y#8ccd70, [1, 2, 3])
26:  [spy] << FAIL
‘ [spy]’で始まっている行がトレースの出力です. そうでない3,8,13,18行目がprint文の出力結果になっています(解は4つありましたね).
1,4,6,9,11,14,16,19,21,23,25行目は同じ形をしていますが,これは,述語の呼出し,あるいは再呼出しが行われたことを表わしています. ‘[spy]’に続く‘x<y,z>’は,次のことを意味します.
x:‘C’ならば呼出し(CALL)を,‘R’ならば再呼出し(REDO)を表わします.
y:一つの述語に対する一連の評価を区別するための識別子です.
z:評価の回数です.0ならば最初の呼出し,1以上ならば再呼出しの回数を表わします.
変数は,‘_’+(変数名)+(変数を一意に識別する値)の形式で表示されます.
これらの行に続いて,呼出しの結果が出力されます.
‘>>’は,事実と単一化が成功したことを表わします.
‘=>’は,規則と単一化が成功したことを表わします.
‘<< FAIL’は,失敗を表わします.
‘>>’や,‘=>’の後には,どの事実/規則と単一化されたか,新たなゴール節は何かという情報が出力されています. 見ればわかりますね.

組込み述語や,コールバックが設定されているときには,これら以外の情報も出力されます. やはり‘ [spy]’で始まります.これらも意味は見ればわかるでしょうから,ここでは省略します.

[Next]コールバック [Previous]結果の処理 [Up]PoPの使用方法 [Top]