什么是"逻辑纯度" (在Prolog编程的背景下)? logical-purity标记信息表示仅使用Horn子句" 的"程序,但是,像if_/3
这样的谓词如何符合条件,使用尽可能多的cut,以及各种元逻辑(什么是正确的术语?var/1
等)谓词,即低级别的东西。
我明白它实现了一些纯粹的"效果,但这究竟是什么意思呢?
有关更具体的说明,请说明if_/3
如何符合逻辑纯度,在使用中可见,例如in this answer?
答案 0 :(得分:10)
让我们首先习惯声明性读取逻辑程序。
声明性地,Prolog程序声明什么是真的。
例如
natural_number(0).
natural_number(s(X)) :-
natural_number(X).
第一个条款规定:0
是一个自然数。
第二个条款规定:如果 X
是自然数,则 s(X)
是自然数。
现在让我们考虑一下这项计划变更的影响。例如,当我们改变这两个条款的顺序时会发生什么变化?
natural_number(s(X)) :-
natural_number(X).
natural_number(0).
声明地说,交换条款的顺序并不会以任何方式改变程序的预期含义(分离是可交换的)。
操作上,也就是说,考虑到Prolog的实际执行策略,不同的子句顺序通常会产生显着的差异。
然而,无论选择的子句排序如何,都会保留纯Prolog代码的一个非常好的属性:
如果查询
Q
成功有关订购O1
的子句,那么 使用不同的排序Q
{/ 1}} 不会失败。
请注意,我不表示O2
总是也成功使用不同的顺序:这是因为查询也可能循环或产生不同排序的错误。
对于两个查询Q
和Q1
,我们说Q2
更通用如果它包含G1
语法统一。例如,查询G2
比查询?- parent_child(P, C).
更通用。
现在,通过纯Prolog程序,另一个非常好的属性成立:
如果查询
?- parent_child(0, s(0)).
成功,则每个更通用的查询Q1
都不会 失败
再次注意,Q2
可能会循环而不是成功。
现在考虑你提到的Q2
的情况,并考虑相关的谓词var/1
。假设我们有:
nonvar/1
这是什么时候举行的?显然,如果参数不是变量,它就成立。
正如所料,我们得到:
my_pred(V) :-
nonvar(V).
但是,对于更一般的查询?- my_pred(a).
true.
,我们得到:
?- my_pred(X).
这样的谓词称为非单调,由于此属性,您不能将其视为真正的关系:这是因为上面的答案?- my_pred(X).
false.
在逻辑上意味着存在< em>没有任何解决方案,但在前面的例子中,我们看到是解决方案。因此,通过添加约束构建的更具体的查询不合逻辑地使查询成功:
false
因此,关于这种谓词的推理非常复杂,以至于与它们一起编程并不是一件好事。它使声明性调试变得不可能,并且难以声明保留的任何属性。例如,只是在上面的连接查询中交换子目标的顺序将使它失败:
?- X = a, my_pred(X).
true.
因此,我强烈建议保留在Prolog的纯粹单调子集中,这允许按照上述方式进行声明性推理。
CLP(FD)约束,?- my_pred(X), X = a.
false.
等在这个意义上都是纯:无论模式,订单等在哪里,你都不能欺骗这些谓词给出逻辑上无效的答案。你用它们。 dif/2
也满足此属性。另一方面,if_/3
,var/1
,nonvar/1
,integer/1
,具有副作用等的谓词都是在逻辑上引用声明性世界之外的东西。描述,因此不能被认为是纯粹的。
编辑:澄清:我在这里提到的不错的属性绝不是详尽无遗的。 Pure Prolog代码展示了许多其他非常有价值的属性,通过它们可以感知逻辑编程的荣耀。例如,在纯Prolog代码中,添加一个子句最多可以 extend ,而不是缩小,解决方案集;添加目标最多可以缩小,永远不会延伸,等等。
使用单个额外逻辑原语可能并且通常会破坏许多这些属性。因此,例如,每次使用!/0
时,将其视为 cut 直接进入纯洁的核心,并试图为伤害这些属性感到遗憾和羞耻。
一本好的Prolog书至少会开始介绍或包含许多提示,以鼓励这样的声明性观点,引导你思考更一般的查询,保留的属性等.Bad Prolog书籍对此并不会说太多最终使用那些破坏语言最有价值和最美丽属性的不纯语言元素。
一个令人敬畏的Prolog教学环境,广泛使用这些属性来实现声明性调试,称为GUPU,我强烈建议您查看这些想法。 Ulrich Neumerkel慷慨地提出了一个在他的环境中使用的核心思想,部分可用library(diadem)。请参阅源文件以获取有关如何以声明方式调试意外失败的目标的良好示例:库系统地构建仍然失败的查询的泛化。这种推理当然可以完美地使用纯代码。