4

在下面给出的代码中,有一个!(cut) 修剪了选择点以提高效率。我很确定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).
4

1 回答 1

7

上面例子中的 cut 有以下效果:

理想情况下,它将可能发生的搜索提交solve_task_a/6到找到的第一个答案。这可以释放资源来寻找进一步的答案,从而改善空间消耗。

范围问题

然而,与此同时,它也可能隐藏更多的答案agent_current_position/2。当然,对于这个目标有进一步的答案没有多大意义,但它可能是一个错误,恰好休眠了一段时间,只是变得活跃但在最坏的情况下仍然未被发现。

出于这个原因,最好是写而不是剪切

    ...,
    once( solve_task_a( ... ) ),
    ...

这将范围精确地限制为您想要表达的内容。

稳定性问题

但这并不是问题的唯一可能来源。我看到了这个变量Cost。当您调用时它会被实例化solve_task(Task, Cost)吗?我可以在这里做很多猜测。但至少这个变量可能会影响 Prolog 承诺的答案。因此solve_task(Task, 99),并且solve_task(Task, Cost), Cost = 99可能会产生不同的答案。事实上,后者甚至可能失败。据说有这些问题的谓词缺乏稳定性

为了说明在这种情况下如何容易失去坚定性,请考虑您的(已经改进的)程序的这个(可运行的)草图:

解决任务(任务,成本):-
    % agent_current_position(奥斯卡,P),
    一次(solve_task_a(任务,[b(0,0,P)],[],R,Cost,_NewPos)),
    真的。

解决任务_a(_,_,_,_,20,_)。
解决任务_a(_,_,_,_,30,_)。

现在

?- solve_task(a, Cost).
Cost = 20.

?- solve_task(a, 30).
true.

?- solve_task(a, Cost), Cost = 30.
false.

通过干净地测试变量将有一个简单的方法来解决这个问题Cost,例如Cost >= 0,产生实例化错误的应该Cost是一个未实例化的变量。但是如果你想(正如你在评论中指出的那样)确定成本,你需要这样写:

解决任务(任务,成本):-
    % agent_current_position(奥斯卡,P),
    一次(solve_task_a(任务,[b(0,0,P)],[],R,CostX,_NewPos)),
    成本X = 成本
    真的。

通过这种方式,我们可以确定Cost不会影响(euh - 如果和solve_task_a/6之间没有混叠- 但我们暂时假设) 的结果。有人还说输出统一放在了 commit 后面CostTask

许多人会告诉您,不需要这种额外的护理,因为您永远不会solve_task(Task, Cost)以给定的成本使用。可能是这样,但你确定你会记得吗?你确定源代码会记住它(没有任何动态检查)?如果你的心智能力负担过重,这种隐含的假设很容易累积到一定程度。

并不总是有一个简单的出路。但通常可以坚持逻辑纯度。在这种情况下,您不必记住任何此类假设。


无论如何,我建议您暂时不要进入 Prolog 的这些部分。而是坚持使用和其他保持干净、单调的程序。有很多东西要学!

于 2015-06-14T08:38:28.463 回答