具有多个结果的Prolog目标

时间:2018-12-02 10:25:50

标签: prolog prolog-toplevel

spec(comp1, pc, 32).                                      /* Fact  1 */
spec(comp2, mac, 128).                                    /* Fact  2 */
spec(comp3, pc, 64).                                      /* Fact  3 */
runs(pc, movie_edit, 96).                                 /* Fact  4 */
runs(pc, vb, 16).                                         /* Fact  5 */
runs(pc, cpp, 28).                                        /* Fact  6 */
runs(mac, vb, 24).                                        /* Fact  7 */
runs(mac, prolog, 128).                                   /* Fact  8 */
access(judy, comp1).                                      /* Fact  9 */
access(peter, comp3).                                     /* Fact 10 */
access(david, comp1).                                     /* Fact 11 */
access(david, comp2).                                     /* Fact 12 */
can_use(P, SW) :- access(P, Comp), can_run(Comp, SW).     /* Rule  1 */

can_run(Comp, SW) :- spec(Comp, CompType, MemAvail),
                   runs(CompType, SW, MemNeeded),
                   MemAvail >= MemNeeded.               /* Rule   2 */

?- can_use(judy, vb).
?- can_use(david, prolog).

第一个目标返回:true,false。 而第二个仅返回true。
我的问题是,为什么在第一个目标中拥有这些额外的信息。
我正在使用SWI-Prolog 7.6.4版本

1 个答案:

答案 0 :(得分:1)

发生这种情况的原因是,在前一种情况下,仍然存在“ 机会”进行回溯,而在后一种情况下,则没有这种机会。

如果我们用trace调用目标,则会看到:

[trace]  ?- can_use(judy, vb).
   Call: (8) can_use(judy, vb) ? creep
   Call: (9) access(judy, _2968) ? creep
   Exit: (9) access(judy, comp1) ? creep
   Call: (9) can_run(comp1, vb) ? creep
   Call: (10) spec(comp1, _2968, _2970) ? creep
   Exit: (10) spec(comp1, pc, 32) ? creep
   Call: (10) runs(pc, vb, _2970) ? creep
   Exit: (10) runs(pc, vb, 16) ? creep
   Call: (10) 32>=16 ? creep
   Exit: (10) 32>=16 ? creep
   Exit: (9) can_run(comp1, vb) ? creep
   Exit: (8) can_use(judy, vb) ? creep
true ;
   Redo: (10) runs(pc, vb, _2970) ? 

因此,我们在这里用runs/3呼叫runs(pc, vb, MemNeeded),Prolog用16找到了第一个答案。但这为使用runs/3查找其他runs(pc, vb, MemNeeded)事实提供了一个回溯点。想象一下,在源代码的后面还有另一个事实,例如末尾的runs(pc, vb, 14),那么这可以产生另一个答案。

但是,如果我们将第二个目标称为“目标”,则可以看到:

[trace]  ?- can_use(david, prolog).
   Call: (8) can_use(david, prolog) ? creep
   Call: (9) access(david, _3726) ? creep
   Exit: (9) access(david, comp1) ? creep
   Call: (9) can_run(comp1, prolog) ? creep
   Call: (10) spec(comp1, _3726, _3728) ? creep
   Exit: (10) spec(comp1, pc, 32) ? creep
   Call: (10) runs(pc, prolog, _3728) ? creep
   Fail: (10) runs(pc, prolog, _3728) ? creep
   Fail: (9) can_run(comp1, prolog) ? creep
   Redo: (9) access(david, _3726) ? creep
   Exit: (9) access(david, comp2) ? creep
   Call: (9) can_run(comp2, prolog) ? creep
   Call: (10) spec(comp2, _3726, _3728) ? creep
   Exit: (10) spec(comp2, mac, 128) ? creep
   Call: (10) runs(mac, prolog, _3728) ? creep
   Exit: (10) runs(mac, prolog, 128) ? creep
   Call: (10) 128>=128 ? creep
   Exit: (10) 128>=128 ? creep
   Exit: (9) can_run(comp2, prolog) ? creep
   Exit: (8) can_use(david, prolog) ? creep
true.

这里我们称runs(mac, prolog, MemNeeded).,这是runs/3的最后事实,因此没有其他可能性满足runs/3:否则,由于Prolog自上而下运行,如果满足了最后一个事实/条款,我们知道别无选择。

由于所有其他调用也都采用了最后一个谓词,或者以不同的常量作为第一个参数(SWI-Prolog在将源代码作为优化进行编译时会查看第一个参数),因此没有其他回溯点,因此无法Redo进行某个呼叫。