为什么 Prolog 的否定失败不被视为逻辑否定?

Pen*_*ope 5 logic prolog negation negation-as-failure

在许多 Prolog 指南中,以下代码用于说明 Prolog 中的“失败否定”。

not(Goal) :- call(Goal), !, fail. 
not(Goal).
Run Code Online (Sandbox Code Playgroud)

然而,这些相同的教程和文本警告说,这不是“逻辑否定”。

问题:有什么区别?

我试图进一步阅读这些文本,但它们没有详细说明其中的区别。

Tes*_*ler 5

  • 逻辑主张:“有一只黑天鹅”。

  • Prolog 声称:“我发现了一只黑天鹅”。

这是一个强有力的主张。

  • 逻辑否定:“不存在黑天鹅”。

  • Prolog 否定:“我还没有发现黑天鹅”。

没有那么强烈的主张;逻辑版本没有黑天鹅的空间,Prolog 版本确实有空间:代码中的错误,质量差的代码不能到处搜索,有限的资源限制搜索整个宇宙到天鹅大小的区域。

逻辑否定不需要任何人去寻找任何地方,该主张独立于任何证据或反驳。Prolog 逻辑纠结于 Prolog 可以使用您编写的代码证明什么,不能证明什么。


lam*_*y.x 5

我喜欢@TesselationHeckler 的回答,因为它指出了问题的核心。您可能仍然想知道,这对于 Prolog 来说更具体意味着什么。考虑一个简单的谓词定义:

p(something).
Run Code Online (Sandbox Code Playgroud)

从根本上讲,我们得到了查询的预期答案:

?- p(something).
true.

?- \+ p(something).
false.

?- p(nothing).
false.

?- \+ p(nothing).
true.
Run Code Online (Sandbox Code Playgroud)

当变量和替换发挥作用时,问题就开始了:

?- \+ p(X).
false.
Run Code Online (Sandbox Code Playgroud)

p(X)并不总是假的,因为它p(something)是真的。到目前为止,一切都很好。让我们使用相等来表达替换并检查是否可以通过\+ p(nothing)这种方式导出:

?- X = nothing, \+ p(X).
X = nothing.
Run Code Online (Sandbox Code Playgroud)

从逻辑上讲,目标的顺序并不重要。但是当我们想要导出重新排序的版本时,它失败了:

?- \+ p(X), X = nothing.
false.
Run Code Online (Sandbox Code Playgroud)

不同之处在于X = nothing, \+ p(X),当我们到达那里的否定时,我们已经统一了,X以便 Prolog 尝试推导\+p(nothing)我们知道是真的。但在另一个顺序中,第一个目标是更一般的目标\+ p(X),我们看到它是错误的,让整个查询失败。

这当然不应该发生——在最坏的情况下,我们会期望不终止,但永远不会失败而不是成功。

因此,我们不能再依赖对子句的逻辑解释,而必须在涉及否定时立即考虑 Prolog 的执行策略。

  • 这里的问题是,一般来说 `\+ p(X)` 会失败,因为如果您尝试导出 p(X),您会正确地得到一个 `X=something` 的反例。在“\+ p(X), X = Nothing”情况下发生的情况是,“X”在查询的第一个目标中仍然未绑定,因此它已经失败,而无需检查“X = Nothing”。这是由于否定的非构造性定义方式造成的。从逻辑的角度来看,它应该是不同的,因为从 ∃X Øp(X) ∧ X = Nothing 我当然可以推断 Øp(nothing) ∧ Nothing = Nothing - 这不是 Prolog 中发生的情况。 (2认同)

fal*_*lse 5

有几个原因,

实例化不足

一个目标not(Goal_0)将会失败,当且仅当在执行该目标Goal0的时间点成功。因此,它的含义取决于执行该目标时恰好出现的实例。改变目标的顺序可能会改变结果。所以合取是不可交换的。not/1not/1

有时,可以通过重新编写实际查询来解决此问题。

防止错误答案的另一种方法是检查目标是否已充分实例化,方法是检查 sayground(Goal_0)是否为真,否则会产生实例化错误。这种方法的缺点是经常会产生实例化错误,而人们不喜欢它们。

甚至还有一种方法是适当延迟执行Goal_0。提高这种方法的粒度的技术称为构造性否定。您会发现很多关于它的出版物,但它们还没有进入通用 Prolog 库。原因之一是,当存在许多延迟目标时,此类程序特别难以调试。

当将 Prolog 的否定与约束结合起来时,事情会变得更糟。想想X#>Y,Y#>X哪个没有解决方案,但not/1只是看到它的成功(即使这种成功是有条件的)。

语义歧义

如果普遍否定,Prolog 认为存在一个最小模型的观点就不再成立。只要只考虑分层程序,这就不是问题。但是有许多程序没有分层但仍然是正确的,例如实现否定的元解释器。一般情况下有几个最小模型。解决这个问题远远超出了 Prolog 的范围。

学习Prolog时首先要坚持纯粹、单调的部分。这部分比许多人预期的要丰富得多。无论如何,你都需要掌握这一部分。

  • 以:“p :- p.”开头,其中“p”可以是“true”或“false”以使其为真。Prolog 选择“false”。 (2认同)