Prolog中的"逻辑纯度"是什么意思?

Wil*_*ess 14 logic prolog logical-purity

什么是"逻辑纯度"(在Prolog编程的背景下)?该标记信息说,"使用程序只喇叭条款",但随后又怎么会谓词喜欢if_/3出线,使用因为它切为多,和各种元逻辑(什么是适当的术语?var/1和这样)谓词,即低级别的东西.

我明白它实现了一些"纯粹"的效果,但这究竟是什么意思呢?

有关更具体的说明,请解释如何if_/3符合逻辑纯度,在使用看到,例如在此答案中

mat*_*mat 10

让我们首先习惯逻辑程序的声明性读取.

声明地说,Prolog程序说明了什么是真的.

例如

natural_number(0).
natural_number(s(X)) :-
        natural_number(X).
Run Code Online (Sandbox Code Playgroud)

第一个条款规定:0是一个自然数.

第二个条款规定:如果 X是自然数, s(X)是自然数.

现在让我们考虑一下这项计划变更的影响.例如,当我们改变这两个条款的顺序时会发生什么变化?

natural_number(s(X)) :-
        natural_number(X).
natural_number(0).
Run Code Online (Sandbox Code Playgroud)

声明地说,交换条款的顺序并不会以任何方式改变程序的预期含义(分离是可交换的).

在操作上,也就是说,考虑到Prolog的实际执行策略,不同的子句命令显然经常会产生显着的差异.

但是,无论选择的子句排序如何,都会保留纯Prolog代码的一个非常好的属性:

如果查询在子句排序方面Q 成功O1,则 Q 不会因不同的顺序而失败O2.

请注意,我并不是Q总是以不同的顺序成功:这是因为查询也可能循环或产生具有不同排序的错误.

对于两个查询Q1Q2,我们说G1更普遍的当且仅当它涵括G2相对于语法统一.例如,查询?- parent_child(P, C).更普遍比查询?- parent_child(0, s(0))..

现在,通过纯Prolog程序,另一个非常好的属性成立:

如果查询Q1成功,则每个更通用的查询Q2 都不会失败.

请注意,这Q2可能会循环而不是成功.

现在考虑var/1你提到的情况,并考虑相关的谓词nonvar/1.假设我们有:

my_pred(V) :-
        nonvar(V).
Run Code Online (Sandbox Code Playgroud)

什么时候举行?显然,如果参数不是变量,它就成立.

正如所料,我们得到:

?- my_pred(a).
true.
Run Code Online (Sandbox Code Playgroud)

但是,对于更一般的查询?- my_pred(X).,我们得到:

?- my_pred(X).
false.
Run Code Online (Sandbox Code Playgroud)

这样的断言被称为非单调,你不能把它当作一个真正的关系,因为这个属性:这是因为答案false以上逻辑意味着,有没有解决方案的任何,但紧接着前面的例子中,我们看到有一个办法.因此,不合逻辑地,通过添加约束构建的更具体的查询使查询成功:

?- X = a, my_pred(X).
true.
Run Code Online (Sandbox Code Playgroud)

因此,对这种谓词的推理是非常复杂的,以至于与它们一起编程完全没有意义.它使声明性调试变得不可能,并且难以声明保留的任何属性.例如,只是在上面的联合查询中交换子目标的顺序将使它失败:

?- my_pred(X), X = a.
false.
Run Code Online (Sandbox Code Playgroud)

因此,我强烈建议保留在Prolog的纯粹单调子集中,这允许沿着上面概述的线进行声明性推理.

CLP(FD)约束dif/2等在这个意义上都是纯粹的:你不能欺骗这些谓词给出逻辑上无效的答案,无论你使用它们的模式,命令等.if_/3也满足这个属性.在另一方面,var/1,nonvar/1,integer/1,!/0,谓词与副作用等,都是被描述声明世界之外的所有额外逻辑引用东西,因此不能认为是纯粹的.

编辑:澄清:我在这里提到的不错的属性绝不是详尽无遗的.Pure Prolog代码展示了许多其他非常有价值的属性,通过它们可以感知逻辑编程的荣耀.例如,在纯Prolog代码中,添加一个子句最多可以扩展,而不是缩小解决方案集; 添加目标最多可以缩小,永不延伸,等等.

使用单个额外逻辑原语可能并且通常会破坏许多这些属性.因此,例如,每次使用时!/0,都认为它是切入纯洁心脏的切口,并试图为伤害这些属性而感到后悔和羞耻.

一本好的Prolog书至少会开始介绍或包含许多提示来鼓励这样的声明性观点,引导你思考更一般的查询,保留的属性等等.Pre Prolog书籍不会对此有太多了解并且通常最终会使用正是那些不纯的语言元素破坏了语言最有价值和最美丽的属性.

一个令人敬畏的Prolog教学环境,广泛使用这些属性来实现声明性调试称为GUPU,我强烈建议您查看这些想法.Ulrich Neumerkel慷慨地提出了一个核心思想,在他的环境中使用,部分可用作图书馆(王冠).请参阅源文件以获取有关如何以声明方式调试意外失败的目标的良好示例:库系统地构建仍然失败的查询的泛化.这种推理当然与纯代码完美配合.

  • 我还在阅读,但是,如果Prolog为子目标选择*乐观的*评估策略(条款,或者正确的名称 - 搜索图的子节点)会不会更好:并行执行所有操作选一个最早完成的!然后就不会有那么多的终止问题(重新:*成功*对*不会失败*),而且计算资源这些天应该很便宜. (2认同)
  • 非常感谢,这清理了很多事情!我已经从您的标签维基文本中编辑了一点,希望它没关系.:)(我不会接受一段时间,吸引更多的流量,所以人们有机会更多地投票......) (2认同)
  • @mat我注意到你给出了“如果查询 Q1 成功,那么每个更通用的查询 Q2 都不会失败。” 规则,但不是你在其他地方给出的对偶(如果它失败,它的专业化一定不会成功)?另外,也许您有一些指向所有这些来源的链接,其中描述/定义了单调性和泛化/专业化? (2认同)
  • 澄清为什么我区分*成功*和*不会失败*:有几个原因导致程序可能无法成功,其中一个是资源错误(例如,RAM或CPU内核不足等),所以有了额外的资源和其他搜索策略,就必须加以区分.我还在帖子中添加了更多材料:是的,双重也支持纯粹的单调程序.我已经澄清说,我在帖子中列出的属性并不详尽,它们只是一些例子,可以让我们了解纯Prolog代码可以实现的声明性推理. (2认同)