在下面给出的代码中,有!(剪切)修剪效率的选择点.我很确定reverse谓词和agent_do_moves谓词是必不可少的.
solve_task(Task,Cost):-
agent_current_position(oscar,P),
solve_task_a(Task,[b(0,0,P)],[],R,Cost,_NewPos),!, % prune choice point for efficiency
reverse(R,[_Init|Path]),
agent_do_moves(oscar,Path).
Run Code Online (Sandbox Code Playgroud)
以上示例中的切割具有以下效果:
理想情况下,它会在第一个找到的答案中提交可能发生的搜索solve_task_a/6.这释放了资源以寻找可以改善空间消耗的进一步答案.
但是,与此同时,它可能还会隐藏更多答案agent_current_position/2.当然,为这个目标找到进一步的答案没有多大意义,但这可能是一个错误,恰好睡了一会儿,只是变得活跃但在最糟糕的情况下仍未被发现.
出于这个原因,最好写而不是削减
...,
once( solve_task_a( ... ) ),
...
Run Code Online (Sandbox Code Playgroud)
这将范围精确地限制为您想要表达的内容.
但这不是问题的唯一可能来源.我看到了这个变量Cost.当你打电话solve_task(Task, Cost)或不打电话时会被实例化吗?我可以在这里做很多猜测.但至少这个变量可能会影响Prolog将承诺的答案.所以solve_task(Task, 99),solve_task(Task, Cost), Cost = 99可能会产生不同的答案.事实上,后者甚至可能会失败.据说有这些问题的谓词缺乏坚定性.
为了说明在这种情况下如何容易丢失坚定性,请考虑(已经改进的)程序的这个(可运行的)草图:
solve_task(Task,Cost):-
% agent_current_position(oscar,P),
once(solve_task_a(Task,[b(0,0,P)],[],R,Cost,_NewPos)),
true.
solve_task_a(_, _, _, _, 20, _).
solve_task_a(_, _, _, _, 30, _).
现在
?- solve_task(a, Cost).
Cost = 20.
?- solve_task(a, 30).
true.
?- solve_task(a, Cost), Cost = 30.
false.
Run Code Online (Sandbox Code Playgroud)
通过干净地测试变量可以很容易地解决这个问题Cost,例如Cost >= 0,产生实例化错误应该Cost是一个未实例化的变量.但是如果你想(如你在评论中指出的那样)确定成本,你需要这样说:
solve_task(Task,Cost):-
% agent_current_position(oscar,P),
once(solve_task_a(Task,[b(0,0,P)],[],R,CostX,_NewPos)),
CostX = Cost
true.
通过这种方式,我们可以确定Cost不会影响结果solve_task_a/6(euh - 假设在Cost和之间没有别名Task- 但我们暂时假设这样).有人说输出统一被置于提交之后.
许多人会告诉你,不需要这种额外的照顾,因为你永远不会solve_task(Task, Cost)以给定的成本使用.可能是这种情况,但你确定你会记得吗?你确定源代码会记住它(没有任何动态检查)吗?如果你的心智能力负担过重,这种隐含的假设很容易累积到一定程度.
并不总是有一个简单的出路.但通常有可能坚持逻辑纯度逻辑纯度.在这种情况下,您不必记住任何此类假设.
无论如何,我建议你暂时不要进入Prolog的这些部分.而是坚持继承算术,clpfd和其他保持逻辑纯度的干净,单调的程序.有很多东西需要学习!