-->

知道什么时候在序言中使用切(Knowing when to use cut in prolog)

2019-07-18 18:56发布

我选了一门中,我学到了一些序言。 我无法弄清楚如何/时使用的削减。 即使我得到削减的总体思路,我似乎无法正确地使用它们。 任何人都可以简单介绍一下它,或者提供“切”一个很好的教程(这不是learnprolognow.org),他们可以推荐?

Answer 1:

TL; DR:不要。

切割修剪的Prolog的搜索树。 也就是说,由于没有切断一个纯粹的Prolog程序,并削减相同的程序,唯一的区别是,与削减计划可能会花无果而终中的分支更短的时间,从而更有效; 可能有较少的答案; 它也可能终止,而原来的程序没有。

听起来很无害......甚至是有用的,不是吗? 嗯,大部分的时间事情比较复杂。

红削减

切口通常的方式使得在不裁员的程序有没有合理的意义使用的。 这样的裁员被称为红色的削减。 在较好的情况下,它被用来实现非单调否定的原始形式。 而在其他一些情况下,它是半否定,半数一些程序上的意义,这是非常难以理解。 不仅对节目的读者也为它的作家。 事实上,往往这样的用途无意缺乏坚定性 。 在任何情况下:这些削减不会被放置到现有程序。 他们是为了在从一开始就计划的权利。

对于这样的红色切口的更结构化的用途中,更好地利用once/1(\+)/1 ,或(;)/2 -如果-则-否则像( If -> Then ; Else )代替。 更妙的是,试图通过发行防范意外的用途,结构instantiation_error秒。 或者使用iwhen/2产生实例错误或when/2 ,其延迟目标(在SWI,YAP,SICStus提供)。

绿色削减

即删除无用choicepoints(也是多余的答案)削减被称为绿色削减。 但要注意:你不能把它们放入你的程序只需按下 有的#00ff00 。 大多数时候,你需要一个干净的只读后卫,以确保有没有办法切断这种轮流#ff0000 。 还有一个简单的方法来安全地删除一些吃剩的choicepoints: call_semidet/1 。 下面是一些相关案例:

  • 什么是SLD树此查询?

  • Prolog的追加与切割操作

  • 什么是最佳的绿色削减接班人算术总和?

  • 实施“最后”的序言

切不能犯

最后,我想指出的是切不提交运营商。 有时候行为有点像,但需要大量的限制是一个。 一个提交的操作员不能(AB)用于实现(\+)/1 。 一个提交要求每个子句彼此独立地试过。 因此,每一个条款,需要一个完整的后卫; 它不能只依赖于经过其他一些条款已首次尝试受审。 此外,承诺将有谓词的每个子句中出现。 切口可以在任何地方发生。



Answer 2:

的切口承诺 Prolog的目标而被证明所做的选择。

必须然后使用时的程序员都知道 ,任何可用的替代不能受审。

最突出的应用是否定的故障实施。

fact(a).
fact(b).

/* 1 */ neg(X) :- call(X), !, fail.
/* 2 */ neg(_).

在这里,我(重新)定义的标准否定操作符,通常这是( \ + )/ 1

?- neg(fact(c)).
true.

call(fact(c))第1条规则不能被证明,和备选规则2然后成功。

?- neg(fact(a)).
false.

因为fact(a) 可以证明,切割失效之前丢弃的备选方案。

?- neg(fact(X)).
false.

至少存在一个未知的X这样的事实(X)取得成功。

?- neg(neg(fact(X))).
true.

双重否定有变量没有得到约束的效果。 做元编程时,在不改变其“结构”来获取条款这可能是有用的。 从操作角度来看,很明显(?)这是怎么回事,但该程序确实失去其声明属性。

另一种用途,只有在基本的解释是有用的,是指导进行最后一次通话的优化系统,附加了一个切递归调用。 然后该系统能够避免分配通常需要跟踪替代点的堆栈空间。 一个虚拟的例子:

print_list([E|Es]) :- print_element(E), !, print_list(Es).
print_list([]).

编辑有关的教程:我发现,由威廉Clocksin“条款和效果”包含削减相关的详细调查:第4章“选择和承诺”这是完全致力于削减利弊。 在底线,主要是利弊...



Answer 3:

使用切割之前,我需要我的谓词满足这两个标准:

  • 它给出正确的答案不切
  • 它给出正确的答案,如果条款进行重新排序

一旦我的谓词的行为这种方式,我有时加割伤剪掉不需要确定性。

例如,谓词来测试数是否为正,负或零。

sign(N, positive) :-
    N > 0.
sign(N, negative) :-
    N < 0.
sign(N, zero) :-
    N =:= 0.

每个子句代表完全独立于其他人。 我可以重新排列这些条款或删除条款,其余条款仍然得到所需要的答案。 在这种情况下,我可能把切在年底positivenegative的条款只是告诉Prolog的系统,它不会通过检查其他条款找到更多的解决方案。

人们可以写一个类似的断言不削减使用-> ; ,但有些不喜欢它的外观:

sign(N, Sign) :-
    (   N > 0 -> Sign=positive
    ;   N < 0 -> Sign=negative
    ;            Sign=zero
    ).


Answer 4:

切谓语防止backtracking.Cut谓词被指定为一个感叹号(!)。 切修剪搜索树,并缩短了序言interpreter.Semantically路径跟踪它总是成功。

read(a).
read(b).
color(p, red) :- red(p).
color(p,black) :- black(p),!.
color(p,unknown).

?-color(X,Y).
  X = a,
  Y = red;
  X = b,
  Y = black;

如果不削减目标显示Y =黑后,Y =未知。

有两种类型的切谓词:

绿色剪切:剪切绿色是一种切断这对声明的含义没有影响。 它只是用来提高效率,同时避免不必要的计算。 绿色切削从程序中去除不改变程序的含义。

红切:红切是一个这不会对声明的意义作用。 红切从程序去除改变程序的含义。



Answer 5:

削减几乎从我的代码消失了,一旦我找到了once断言。 在内部,它就像

once(X) :- X, !.

我发现负责就如何我做的东西之前做一些果断的决定是非常有用的。

例如,这里是我的标准元解释。 该maybe1/1条在其参数独特的仿函数所以一旦他们知道,再右边maybe1/1可以选择,非常完美。

发现独特功能的作业给予maybe0/2预处理器,设置Y到“做什么声明”约X

如果没有once ,这可能将不得不削减与百病。 例如在maybe1 ,有三个/两种不同的解释X/Y ,而且or我们需要一个自上而下的方式进行检查。 但检查OUT-没有削减。

maybe(X) :- 
    once(maybe0(X,Y)), maybe1(Y).

maybe0(true,       true).
maybe0((X,Y),      (X,Y)).
maybe0((X;Y),      or(L))          :- o2l((X;Y),L).
maybe0(X,          calls(X))       :- calls(X).
maybe0(X/Y,        fact(X/Y))      :- clause(X/_, true).
maybe0(X/Y,        rule(X/Y))      :- clause(X/_,_).
maybe0(X/Y,        abducible(X/Y)).
maybe0(or([H|T]),  or([H|T])).
maybe0(or([]),     true).

maybe1(true).
maybe1((X,Y))        :- maybe(X),maybe(Y).
maybe1((X;Y))        :- maybe(X);maybe(Y).
maybe1(abducible(X)) :- assume(X,0).
maybe1(fact(X))      :- assume(X,1), one(X).
maybe1(rule(X))      :- assume(X,2), one(clause(X,Y)), maybe(Y).
maybe1(calls(X))     :- one(clause(X,Y)), maybe(Y).
maybe1(or([H|T]))    :- any(One,Rest,[H|T]), ignore(maybe(One)), maybe(or(Rest)).


文章来源: Knowing when to use cut in prolog