“逻辑纯度”是什么意思(在 Prolog 编程的上下文中)?逻辑纯度标签信息说“仅使用 Horn 子句的程序”,但是,如何if_/3
使用限定的谓词,尽可能多地使用它,以及各种元逻辑(什么是正确的术语?var/1
等等)谓词,即低级的东西。
我知道它达到了一些“纯粹”的效果,但这究竟意味着什么?
有关更具体的说明,请解释在使用中例如在此答案中if_/3
看到的逻辑纯的资格?
让我们首先习惯对逻辑程序的声明式阅读。
声明式地,Prolog 程序说明了什么是 true。
例如
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
不会因不同的排序而失败O2
。
请注意,我并不是说Q
总是以不同的顺序成功:这是因为查询也可能循环或产生不同顺序的错误。
对于两个查询Q1
和,如果它包含在句法统一方面Q2
,我们说它G1
更一般。G2
例如,查询?- parent_child(P, C).
比查询更通用?- parent_child(0, s(0)).
。
现在,使用纯 Prolog 程序,另一个非常好的属性成立:
如果查询
Q1
成功,则每个更一般的查询Q2
都不会失败。
请再次注意,这Q2
可能会循环而不是成功。
现在考虑var/1
您提到的情况,并考虑相关的谓词nonvar/1
。假设我们有:
my_pred(V) :-
nonvar(V).
这什么时候举行?显然,如果参数不是变量,则它成立。
正如所料,我们得到:
?- my_pred(a).
true.
但是,对于更一般的查询?- my_pred(X).
,我们得到:
?- my_pred(X).
false.
这样的谓词称为非单调的,由于此属性,您不能将其视为真正的关系:这是因为false
上面的答案在逻辑上意味着没有任何解,但在前面的示例中,我们看到有一个解法。因此,不合逻辑地,通过添加约束构建的更具体的查询使查询成功:
?- X = a, my_pred(X).
true.
因此,对此类谓词进行推理非常复杂,以至于用它们进行编程一点也不好玩。它使声明式调试变得不可能,并且很难声明任何保留的属性。例如,仅在上述连接查询中交换子目标的顺序就会使其失败:
?- my_pred(X), X = a.
false.
因此,我强烈建议留在 Prolog 的纯单调子集内,它允许按照上面概述的路线进行声明性推理。
CLP(FD) 约束dif/2
等在这个意义上都是纯粹的:你不能欺骗这些谓词给出逻辑上无效的答案,无论你使用它们的模式、顺序等。if_/3
也满足这个性质。另一方面,var/1
, nonvar/1
, integer/1
, !/0
, 带有副作用的谓词等都在逻辑上引用了正在描述的声明性世界之外的东西,因此不能被认为是纯粹的。
编辑:澄清一下:我在这里提到的好属性绝不是详尽无遗的。纯 Prolog 代码展示了许多其他非常有价值的属性,通过这些属性您可以感知逻辑编程的荣耀。例如,在纯 Prolog 代码中,添加一个子句最多可以扩展而不是缩小解决方案的集合;添加一个目标最多可以缩小,从不扩展,等等。
使用单个额外逻辑原语可能并且通常会破坏许多这些属性。因此,例如,每次使用时!/0
,都将其视为对纯净之心的切入,并为伤害这些属性而感到遗憾和羞耻。
一本好的 Prolog 书至少会开始引入或包含许多提示来鼓励这种声明性视图,指导您考虑更一般的查询、保留的属性等。糟糕的 Prolog 书不会对此多说,通常最终使用正是那些不纯的语言元素破坏了语言最有价值和最美丽的属性。
一个很棒的 Prolog 教学环境,它广泛使用这些属性来实现声明式调试,称为GUPU,我强烈建议检查这些想法。Ulrich Neumerkel 慷慨地提出了一个在他的环境中使用的核心思想,部分可用作library(diadem)。有关如何以声明方式调试意外失败的目标的良好示例,请参阅源文件:该库系统地构建仍然失败的查询的概括。这种推理当然适用于纯代码。