Prolog中的“逻辑纯度”是啥意思?
Posted
技术标签:
【中文标题】Prolog中的“逻辑纯度”是啥意思?【英文标题】:What is meant by "logical purity" in Prolog?Prolog中的“逻辑纯度”是什么意思? 【发布时间】:2015-11-03 15:46:24 【问题描述】:什么是“逻辑纯度”(在 Prolog 编程的上下文中)? logical-purity 标签信息说 “仅使用 Horn 子句的程序”,但是,像 if_/3
这样的谓词如何限定,尽可能多地使用它,以及各种元逻辑 (什么是正确的术语?var/1
等)谓词,即低级的东西。
我知道它实现了一些“纯粹”的效果,但这究竟意味着什么?
如需更具体的说明,请解释if_/3
如何在使用中被视为逻辑纯,例如in this answer?
【问题讨论】:
好问题,+1!另请查看更长的标签描述以获取更多信息:logical-purity。仅使用 Horn 子句的程序肯定会表现出这些属性。 @mat 啊,你同时编辑了它!如果你可以在这里添加一个答案,扩展更多关于什么是泛化和专业化的信息,也许只有几个例子,那就太好了! (这是关于使用 logvars 代替具体数据,反之亦然,对吗?) w.r.t logvars:我看到这个词的第一反应是:这里使用了什么样的对数方案? @false 嗯!我试图更精确... :) 等等,你没想到 "logging monads"??... Here 是一个相关问题。 【参考方案1】:让我们首先习惯于声明式阅读逻辑程序。
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
不会失败,但顺序不同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)。有关如何以声明方式调试意外失败的目标的良好示例,请参阅源文件:该库系统地构建仍然失败的查询的概括。当然,这种推理完美地使用纯代码。
【讨论】:
我还在阅读,但是,如果 Prolog 为子目标(子句,或正确的名称 -搜索图的子节点):并行执行并选择最早完成的节点!那么就不会有那么多终止问题(re: succeeds vs. does not fail),而且现在计算资源应该很便宜。 非常感谢,这可以清除很多东西!我已经从您的标签 wiki 文本中编辑了一点,希望没问题。 :)(我暂时不会接受,以吸引更多流量,因此人们有机会投票更多...) @WillNess:你在考虑什么并行性? OR- 或 AND- 并行性?如果是 OR-,那么这根本无助于改进通用终止,但是它可能会改进寻找解决方案,但枚举它们变得困难。至于AND-parallelism:这实际上是可能的,但它只在具有逻辑纯度的程序中才有意义。 OTOH:当前纯程序的数量非常非常少,而且通常非常昂贵。 @mat 我注意到你给出了“如果查询 Q1 成功,那么每个更一般的查询 Q2 都不会失败。”规则,但不是你在其他地方给出的双重规则(如果它失败,它的专业化一定不会成功)?此外,也许您有一些指向所有这些来源的链接,其中描述/定义了单调性和泛化/专业化? 澄清为什么我要区分成功和不会失败:程序可能不成功的原因有多种,其中之一是资源错误(例如,RAM 或 CPU 内核不足等),因此还有额外的资源和其他搜索策略,区分将是必要的。我还在帖子中添加了更多材料:是的,对偶也适用于纯单调程序。我已经澄清,我在帖子中列出的属性并非详尽无遗,它们只是几个示例,让您了解纯 Prolog 代码使声明性推理成为可能。以上是关于Prolog中的“逻辑纯度”是啥意思?的主要内容,如果未能解决你的问题,请参考以下文章