Prolog使用削减

时间:2014-05-31 17:53:51

标签: prolog prolog-cut

我在Prolog中重写了以下函数:

V1:

f(X,Y):- X < 2, Y is X+1.
f(X,3):- 2 =< X, X < 5.
f(X,Y):- 5 =< X, Y is 8-X.

作为V2:

f(X,Y) :-
    X < 2,
    Y is X + 1. 
f(X,Y) :-
    X >= 2,
    X < 5,
    Y is 3.
f(X,Y) :-
    X >= 5,
    Y is 8-X.

然后我想尝试削减。绿色削减(V3):

f(X,Y) :-
    X < 2, !,
    Y is X + 1.
f(X,Y) :-
    X >= 2,
    X < 5, !,
    Y is 3.
f(X,Y) :-
    X >= 5,
    Y is 8-X.

红色切割(V4):

f(X,Y) :-
    X < 2, !,
    Y is X + 1.
f(X,Y) :-
    X < 5, !,
    Y is 3.
f(X,Y) :-
    Y is 8-X.

但是,我不明白他们的优势,因为删除剪辑会允许代码的相同行为......有什么帮助吗?

2 个答案:

答案 0 :(得分:1)

你的所有版本V1..V4在观察上是等价的,所以你有一些推理权。但仍然存在差异。

避免多余的选择点

在许多实现中,V1和V2的效率可能特别低,因为在内部,它们“保持开放的选择点”。这是因为这样的Prologs对其他规则没有任何进一步的看法。因此每个目标f(1,X)消耗一些内存,只有在回溯(或使用!)时才能释放。这是一个简单的方法来尝试这个:

loop(Goal) :-
   Goal,
   loop(Goal).

以下是我在SWI中获得的内容:

?- time(loop(f1(1,2))).
% 5,991,554 inferences, 81.282 CPU in 81.443 seconds (100% CPU, 73713 Lips)
ERROR: Out of local stack
?- time(loop(f2(1,2))).
% 5,991,553 inferences, 85.032 CPU in 85.212 seconds (100% CPU, 70462 Lips)
ERROR: Out of local stack

而V3和V4似乎无限期地运行 - 至少比85秒长。像这样的实验对于非常小的程序来说很有趣,但对于较大的程序则不太实用。幸运的是,有一种简单的方法可以告诉许多Prologs查询是否确定执行。要查看您的系统是否执行此操作,请输入:

?- X = 1.
X = 1.

对于您的变体:

?- f1(1,2).
true ;        % <== Prolog asked for another answer
false.        % <== only to conclude that there is none.

?- f2(1,2).
true ;        % same again
false.

?- f3(1,2).
true.         % <== Prolog knows there will be no further answer

?- f4(1,2).
true.

避免重新计算 - 削减红色

虽然V3避免了多余的选择点,但V4现在甚至避免了多余的计算。所以它应该是最有效的。但这是以修复条款顺序为代价的。


然而,V3才有可能,因为绿色削减的两个必要条件是一致的:

  1. 非重叠条件。这对你来说应该是显而易见的。

  2. 安全测试实例化。这远非显而易见。请注意,目标X < 2对附加的正确实例化进行了隐式测试!如果X是未实例化的变量,它会产生实例化错误。正是因为这个测试,V3中的切割恰好是绿色切割。如果没有这种测试,那将是红色的。

  3. 另请注意,如果第二条规则是单独的,V1和V2将不相同!因为目标f(X,5).在V1中会失败,但它会在V2中产生错误。

答案 1 :(得分:0)

正如您所说,第一个版本显示绿色切割和第二个红色切割。 您没有必要感受到这两个版本之间的区别。

a)一个原因可能是效率,但对于快速机器的玩具代码,你几乎没有注意到它。

b)改变规则不应该在绿色削减的情况下改变代码的行为,并且对于第一个代码来说这是正确的。但是在第二个代码中,如果将第二个子句放在第一个子句之前而不是行为更改:f(0,3)为true,但最初它是false。因此,如果你改变规则,你会感到不同。

改组的好处在于你不关心订单而是内容 - 这是声明性编程的要点之一。