【问题标题】:Prolog list membership, multiple results returnedProlog 列表成员资格,返回多个结果
【发布时间】:2013-01-13 17:35:41
【问题描述】:

我有一个确定列表成员资格的标准程序:

member(X, [X|_]).  
member(X, [_|T]) :- member(X, T).

我不明白为什么当我提出以下查询时:

?- member(a,[a,b]).

结果是

True;  
False.

我原以为在使用第一条规则(因为 a 是列表的头部)满足目标时,将返回 True,这将是 if 的结束。似乎它正在尝试使用第二条规则来满足目标并且失败了?

Prolog 解释器是 SWI-Prolog。

【问题讨论】:

  • 您使用的是什么版本的 SWI?
  • @WillNess 6.2.6 64bit for mac

标签: prolog swi-prolog prolog-toplevel


【解决方案1】:

让我们首先考虑一个类似的查询:[编辑:这样做无需添加您自己的定义; member/2 已定义]

?- member(a,[b,a]).
true.

在这种情况下,您会得到最佳答案:只有一种解决方案。但是当交换列表中的元素时,我们得到:

?- member(a,[a,b]).
true ;
false.

从逻辑上讲,两者都只是对查询为真的肯定。

差异的原因是,在第二个查询中,当找到a 作为列表元素时,立即给出答案true。其余列表[b] 不包含拟合元素,但尚未对此进行检查。仅根据请求(点击 SPACE;)尝试列表的其余部分,结果没有进一步的解决方案。

本质上,当计算完全完成以及仍有一些工作要做时,这个微小的差异会给你一个提示。对于简单的查询,这并没有什么不同,但在更复杂的查询中,这些开放的备选方案(选择点)可能会累积并耗尽内存。

即使没有,旧的顶层总是询问您是否想查看进一步的解决方案。

编辑:

避免询问下一个答案(如果没有)的能力很大程度上取决于实现细节。即使在同一个系统中,加载同一个程序,你也可能得到不同的结果。但是,在这种情况下,我使用的是 SWI 的内置定义 member/2,而您使用的是您自己的定义,它会覆盖内置定义。

SWI 使用以下定义作为内置定义,这在逻辑上等同于您的定义,但使 SWI 更容易避免不必要的选择点 - 但许多其他系统无法从中受益:

member(B, [C|A]) :-
        member_(A, B, C).

member_(_, A, A).
member_([C|A], B, _) :-
        member_(A, B, C).

让事情变得更加复杂:许多 Prolog 具有不同的顶层,当查询不包含变量时,它从不要求进一步的答案。所以在那些系统(比如 YAP)中,你会得到错误的印象。

尝试以下查询来查看:

?- member(X,[1]).
X = 1.

SWI 再次能够确定这是唯一的答案。但是 YAP,例如,不是。

【讨论】:

  • 我实际上仍然得到这两个查询的真假答案。在第二个查询中,我不明白为什么当第一个规则已经找到 a 作为列表的头部时它会继续尝试检查 [b]。
  • @Justin 因为你按下了; 按钮。它检查了头部,发现它匹配,并将true 报告给您。但它仍然没有查看列表的其余部分。
  • @WillNess 所以你说即使规则 1 满足查询,规则 2 也会被评估(因此检查列表的尾部 [b] 并失败)?
  • 我现在可以看到我正在运行跟踪您所说的内容是正确的,它尝试测试 member(a, [b]) 并失败。谁能解释它为什么这样做?我是否正确地说,当将目标与规则的头部匹配时,它会在满足目标时返回,但在按下“;”时仍会测试具有匹配头部的其他规则?
  • @Justin 当 Prolog 成功满足查询时,它不会停止,而是暂停。这就是 Prolog 的定义方式。它暂停,记住它的位置,打印结果并等待操作员的命令:';',或'Space','Enter','?'等
【解决方案2】:

你用的是“;”第一个结果之后的运算符然后推返回?我相信这是要求查询寻找更多结果,因为没有结果,所以它是错误的。

【讨论】:

  • 是的,我是。但是,到目前为止,我的经验是,通常在提出只有一个可能结果的查询时,它只会打印 True ,然后返回到 ?- 提示符。这 ”;”运算符通常仅在有多个答案时可用。
【解决方案3】:

你知道 Prolog 的剪辑 - !吗?

如果您将member(X, [X|_]). 更改为member(X, [X|_]) :- !.,Prolog 将不会在第一个解决方案之后尝试寻找另一个解决方案。

【讨论】:

  • 如果没有剪辑,它的行为基本上与您在问题中描述的一样 - “然后尝试使用第二条规则满足目标并失败”。
  • 我明白了。因此,基本上,如果您知道较早的规则是“最佳解决方案”,则可以添加剪辑。缺点是您永远不会知道是否存在另一个有趣的解决方案。
  • member(X,[1,2,3]) 应该给出三个答案/解决方案而不是一个。
  • @Justin:在 Prolog 程序中引入 cut 非常麻烦。在某些情况下,上述许多尝试都会出错。所以最好避免一开始就被删减,有足够的东西可以从无删减程序中学习。
猜你喜欢
  • 1970-01-01
  • 2022-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-12
  • 2014-05-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多