为什么SWI-Prolog的行为看似不一致?

时间:2018-12-25 20:37:03

标签: prolog prolog-toplevel

试图了解Prolog中的 cut-fail 组合,我找到了以下示例并开始使用它:

enjoys(vincent,X)  :-  big_kahuna_burger(X),!,fail. 
enjoys(vincent,X)  :-  burger(X). 

burger(X)  :-  big_kahuna_burger(X). 
burger(X)  :-  big_mac(X). 
burger(X)  :-  whopper(X). 


big_kahuna_burger(b). 
big_mac(a).  
whopper(d).

我尝试了两个不同的查询。

在查询1:enjoys(vincent,b)中,结果是SWI-Prolog输出{{​​1}},这是预期的行为,并且它停止了,并没有问我是否要它寻找更多解决方案

在查询2:false中,第一个SWI-Prolog输出{{​​1}},这也是预期的,但随后它为我提供了单击“ next” 的选项,并尝试找到另一个解决方案,然后输出enjoys(vincent,a)

为什么它让我可以选择在第二个查询期间而不是在第一个查询中检查其他解决方案?

2 个答案:

答案 0 :(得分:3)

简而言之:因为false表示在进行详尽搜索后,找不到(额外)解决方案。

  

为什么它让我可以选择在第二个查询期间而不是在第一个查询中检查其他解决方案?

因为它输出false,这意味着它在详尽的搜索后找不到解决方案。因此,它表示“ 我没有找到任何解决方案(不再)。”。因此,在false之后,搜索多余的解决方案是没有意义的。

但是,在提出解决方案的情况下,(本身)并不意味着所有解决方案都已用尽。因此,它可以提出其他解决方案。根据Prolog解释器的优化,有时它可以预先知道没有其他解决方案。如果不是这种情况,它将打印解决方案,然后暂停。然后,用户可以请求其他解决方案。

例如,如果我们写:

foo(a, 1).
foo(a, 2).
foo(b, 3).
foo(c, 4).

然后,至少在SWI-Prolog中,也许在大多数解释器中,使用foo(b, 3)进行查询时,只会说true,然后知道它已完成。因为SWI-Prolog将分析第一个参数的函子/常数,因此预先知道,如果第一个参数是扎根的,则没有其他foo/2作为第一个参数的b。 / p>

答案 1 :(得分:1)

您的第一个查询已成功完成,这会向Prolog发出信号,要求中止任何进一步的寻找解决方案的尝试。然后,它命中false,这使查询失败并向用户报告false,然后由于剪切已修剪所有可能的进一步搜索,因此Prolog停止。

一个简单的实现很可能会在剪切之后尝试进行搜索,即使是徒劳的,也只是在回溯时立即发现剪切,然后最终停止。

在第二个查询中,big_kahuna_burger(a)失败,并且避免了剪切。将来的搜索空间不会被删除。

burger(a)  :-  big_kahuna_burger(a). 

失败,但是

burger(a)  :-  big_mac(a). 

成功,而且还有

burger(a)  :-  whopper(a). 

尝试。

因此,Prolog完全希望能够找到更多的机会。就像我们的“简单”实现一样,即使在第一种情况下也是如此。

要停止该操作,则需要实施方案提前检查并检查将来的结果,以检测到whopper(a)确实注定要失败。但这总是太昂贵了,而且只能在少数几个非常特殊的情况下(如果有的话)来完成。

我认为这称为“索引编制”。搜索“索引Prolog”会带来很多匹配。