【问题标题】:Prolog goal with multiple results具有多个结果的 Prolog 目标
【发布时间】:2018-12-02 10:25:49
【问题描述】:
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。
我的问题是为什么在第一个目标中我们有额外的信息。
我使用的是 SWI-Prolog 7.6.4 版本

【问题讨论】:

  • 这里你的两个目标是一样的,所以我希望两个都返回true; false.?
  • 非常抱歉,这是一个错误,我已更正。
  • david 的查询不回溯的原因是因为这里每次都选择last 个事实,因此没有机会进一步回溯。跨度>

标签: prolog prolog-toplevel


【解决方案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(pc, vb, MemNeeded) 调用runs/3,Prolog 用16 找到第一个答案。但它设置了一个回溯点,以使用runs(pc, vb, MemNeeded) 查找其他runs/3 事实。想象一下源代码后面还有一个事实,比如末尾有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某个电话。

【讨论】:

  • 感谢您的广泛回答。我只是不明白为什么没有其他回溯点,例如:spec(comp1, _2968, _2970)
  • @Hamza:这在某种程度上取决于解释器。但是很多解释者(包括 SWI-Prolog),看第一个论点,从而确保如果第一个论点有根据,它直接找到正确的事实。因此,它对第一个参数执行某种“索引”。从技术上讲,解释器可以在第二个参数上使用相同的技巧,第一个和第二个参数的组合等。问题当然是所有这些索引是否值得付出努力,所以 iirc,这仅在第一个参数上完成.
猜你喜欢
  • 1970-01-01
  • 2013-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-07-29
相关资源
最近更新 更多