【问题标题】:Why is the behaviour of SWI-Prolog seemingly inconsistent?为什么 SWI-Prolog 的行为看似不一致?
【发布时间】:2018-12-25 20:37:02
【问题描述】:

为了理解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 输出 false 这是预期的行为并且它停止了,不问我是否要它搜索更多的解决方案。

在查询 2:enjoys(vincent,a),第一个 SWI-Prolog 输出 true,这又是预期的,但随后它让我可以选择单击 "next" 并尝试找到另一个解决方案,然后输出false

为什么它让我可以选择在第二个查询期间检查另一个解决方案,但在第一个查询中却没有?

【问题讨论】:

  • 如果它返回false,这意味着它已经彻底搜索过了,这意味着绝对没有解决方案,因此在false之后,没有解决方案可以找不到了。
  • 那为什么在第一个查询中也没有返回 false 呢?
  • false 不是解决方案,false 表示它进行了详尽的搜索,但没有找到任何东西。大多数 Prolog 系统会打印 false(或 no)以表明查询已结束。
  • 在第一个例子中,由于没有解决方案,所以没有理由提示您进一步搜索。已经确定没有解决方案。在第二个示例中,找到解决方案的成功逻辑路径留下了一个选择点,这是规则中的一个点,Prolog 可以继续探索以找到其他解决方案。没有找到任何进一步的解决方案,它说“假”。
  • @marc-s 我不得不回滚您的编辑,因为除了修复一个微不足道的错字之外,它还以多种方式打破了这个问题。 Prolog 不会“返回”选项作为其查询用户交互的一部分,它确实将它们“提供”给用户,就像 OP 最初写的那样。最好不要干涉你没有足够能力判断结果的情况,你不同意吗?例如,我永远不会尝试改进任何半连贯的帖子,例如sql-server 标记,永远。干杯。

标签: prolog prolog-toplevel


【解决方案1】:

简而言之:因为false 意味着在详尽搜索之后,找不到(额外的)解决方案。

为什么它让我可以选择在第二个查询期间检查另一个解决方案,但在第一个查询中却没有?

因为如果它输出false,这意味着它在穷举 搜索后未能找到解决方案。因此它的意思是“我没有找到任何解决方案(不再)。”。因此,在false 之后,寻找额外的解决方案是没有意义的。

但是,如果它提出了一个解决方案,这并不(本身)意味着所有解决方案都已用尽。所以它可以提出额外的解决方案。根据 Prolog 解释器的优化,它有时可以提前知道没有额外的解决方案。如果不是这种情况,它会打印解决方案,然后暂停。然后用户可以请求额外的解决方案。

例如,如果我们写:

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

然后用foo(b, 3) 查询,至少在SWI-Prolog 中,可能在大多数解释器中,只说true,然后就知道它已经完成了。因为SWI-Prolog会分析第一个参数的functor/constant,从而提前知道,如果第一个参数接地,则没有其他foo/2s以b为第一个参数。

【讨论】:

  • 有时可以提前知道没有额外的解决方案,但事实并非总是如此,它回答了我的问题。因为查询enjoys(vincent,d) 返回true 而不要求额外的解决方案,但enjoys(vincent,a) 返回true 并且还要求额外的解决方案。我一直假设它总是知道是否有其他解决方案。
【解决方案2】:

您的第一个查询成功了,这向 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) 确实注定要失败。但这样做的成本太高,而且仅在极少数非常特殊的情况下(如果有的话)进行。

我认为这被称为“索引”。搜索“indexing Prolog”会得到很多结果。

【讨论】:

    猜你喜欢
    • 2016-03-31
    • 1970-01-01
    • 2021-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-13
    相关资源
    最近更新 更多