【问题标题】:What is wrong with this version of trace?这个版本的跟踪有什么问题?
【发布时间】:2022-04-12 22:17:26
【问题描述】:

我有这个追踪元解释器。它是为 swi-prolog 编写的。

trace(Goal):-
        trace(Goal, 0).

trace(true, _Depth):-!, true.
trace(fail, _Depth):-!, fail.
trace(A > B, _Depth):-!, A > B.
trace(A < B, _Depth):-!, A < B.
trace(A <= B, _Depth):-!, A <= B.
trace(A >= B, _Depth):-!, A >= B.
trace(A = B, _Depth):-!, A = B.
trace(A is B, _Depth):-!, A is B.
trace(!, _Depth):-!, fail.
trace(not(A), _Depth):-!, not(A).
trace((Goal1, Goal2), Depth):-!,
        trace(Goal1, Depth),
        trace(Goal2, Depth).
trace(Goal, Depth):-
        display('Call: ', Goal, Depth),
        clause(Goal, Body),
        Depth1 is Depth + 1,
        trace(Body, Depth1),
        display('Exit: ', Goal, Depth),
        display_redo(Goal, Depth).
trace(Goal, Depth):-
        display('Fail: ', Goal, Depth),
        fail.

display(Message, Goal, Depth):-
        tab(Depth), write(Depth), write(': '), write(Message),
        write(Goal), nl.

display_redo(Goal, Depth):-
        true
        ;
        display('Redo: ', Goal, Depth),
        fail.

just_do_it(In, Out, Query):-
        consult(In),
        tell(Out),
        call_with_depth_limit(findall(Query, trace(Query), _Solutions), 30, _XMessage),
        writeln(_XMessage),
        writeln(_Solutions),
        told,
        unload_file(In),
        true.

它工作正常,除了一件事外它应该如何工作。当我在函数just_do_it(In, Out, Query) 中有变量Query 时,输出是绑定变量。有没有办法在跟踪的进一步步骤中取消绑定变量,以便我可以看到它什么时候被绑定,什么时候不被绑定?

示例输出:

0: Call: a(_G1085,_G1085,_G1087)
0: Exit: a(3,3,7)
0: Redo: a(3,3,7)
  1: Call: b(_G1087,_G1085)
  1: Exit: b(7,3)
  1: Redo: b(7,3)
  1: Exit: b(5,1)
  1: Redo: b(5,1)
  1: Fail: b(_G1087,_G1085)
0: Fail: a(_G1085,_G1085,_G1087)

我希望得到的示例输出:

0: Call: a(_G1085,_G1085,_G1087)
0: Exit: a(3,3,7)
0: Redo: a(_G1085,_G1085,_G1087)
 1: Call: b(_G1087,_G1085)
 1: Exit: b(7,3)
 1: Redo: b(_G1087,_G1085)
 1: Exit: b(5,1)
 1: Redo: b(_G1087,_G1085)
 1: Fail: b(_G1087,_G1085)
0: Fail: a(_G1085,_G1085,_G1087)

【问题讨论】:

  • 续集:@​​987654321@

标签: prolog prolog-metainterpreter


【解决方案1】:

您的口译员有几个问题:

您正在使用不存在的运算符&lt;=。所以你必须得到一个语法错误。在 Prolog 中小于或等于 =&lt; 以避免与箭头 ⇐ / &lt;= 混淆。

您正在定义一个谓词trace/1,但是 SWI 和许多其他 Prolog 一样已经预定义了这个谓词。所以最好用另一个名字。

剪切没有正确执行。

not/1 的规则应该定义(\+)/1,并且可以这样写:

trace(\+A, Depth):-!, \+trace(A, Depth).

证明变量应生成instantiation_error。比如call(_)。所以你需要作为第一条规则

trace(V, _) :- var(V), !, throw(error(instantiation_error, _)).

要正确显示重做,您需要用更明确的方式替换目标clause(Goal, Body),。毕竟,除了回溯之外,没有办法解绑变量。也就是说,我们必须找到变量仍未实例化的正确时刻。 将clause/2 替换为redo_clause/3

redo_clause(Depth, Goal, Body) :-
   findall(Goal-Body, clause(Goal, Body), [First|Rest]),
   ( Goal-Body = First
   ; length(Rest, RL), length(RestC, RL),
     member(Goal-Body,RestC),
     display('Redo: ', Goal, Depth),
     Rest = RestC
   ).

【讨论】:

  • 我听取了您的建议,并用命名和运算符更改了解释器。然而这并不能解决我的问题。我编辑了我的问题并添加了示例输出和我希望的输出。
  • 我把它标记为答案,它真的对我有帮助,因为你可以说我是序言菜鸟。您提到 cut 没有正确实现,您能告诉我它有什么问题吗?
  • 我发现,现在它不显示深度为 0 的呼叫和重做,仅退出。我试图在 swipl 中进行跟踪,并且有一些我无法解决的故障。当 redo_clause/3 存在时,就会发生这种情况。你知道为什么会这样吗?
  • @Đrakenus: 提问!我确实在 0 级看到重做。
  • 我的错误,这应该是cut的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-27
  • 2015-05-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多