使用 Prolog 在 CLP(R) 中编写递归函数的正确方法

Correct way of writing recursive functions in CLP(R) with Prolog

我对 CLP 在 Prolog 中的工作方式感到很困惑。我不仅发现很难看到好处(我确实在特定情况下看到它,但发现很难概括这些好处)而且更重要的是,我几乎无法弥补如何正确编写递归谓词。以下哪项是 CLP(R) 方式的正确形式?

factorial(0, 1).
factorial(N, F):- {
  N > 0,
  PrevN = N - 1,
  factorial(PrevN, NewF),
  F = N * NewF}.

factorial(0, 1).
factorial(N, F):- {
  N > 0,
  PrevN = N - 1,
  F = N * NewF},
  factorial(PrevN, NewF).

换句话说,我不确定什么时候应该在约束之外编写代码。对我来说,第一种情况似乎更合乎逻辑,因为 PrevNNewF 属于约束条件。但如果那是真的,我很想知道在什么情况下在递归函数.

中使用约束之外的谓词是有用的

您的 post 中有几个重叠的问题和问题,可能太多而无法在一个 post.

中连贯地解决以使您完全满意

因此,我想先说明一些一般原则,然后在此基础上对您 post 编辑的代码提出一些具体的意见。

首先,我想谈谈我认为对你的情况最重要的事情:

LP ⊆中电

简单来说,CLP可以看作是逻辑程序设计(LP)的超集。它是否被认为是 适当的 超集,或者实际上,将它们视为表示相同概念是否更有意义,这有些值得商榷。在我个人看来,没有约束的逻辑编程比约束的逻辑编程更难理解,也更不可用。鉴于即使是第一个 Prolog 系统也有像 dif/2 这样的约束,并且像 (=)/2 这样的基本内置谓词完全符合 "constraint" 的概念,边界,如果它们存在于所有,对我来说至少有点做作,暗示:

LP≈中电

尽管如此,使用 CLP(任何类型的)时的关键概念是 约束 可用作 谓词,并像所有其他谓词一样在 Prolog 程序中使用。

所以不管你的目标是factorial(N, F)还是{ N > 0 },原则上至少,同一个概念:两者 表示 持有

请注意 语法 :CLP(ℛ) 约束的形式为 { C },即前缀表示法中的 {}(C)

请注意,目标 factorial(N, F) 而不是 CLP(ℛ) 约束!以下也不是:

?- { factorial(N, F) }.
ERROR: Unhandled exception: type_error({factorial(_3958,_3960)},...)

因此,{ factorial(N, F) } 也不是 CLP(ℛ) 约束!

因此,您的第一个示例无法工作仅出于这个原因已经。 (另外,你的子句头有一个语法错误:factorial (,所以它也根本无法编译。)

当您学习使用约束求解器时,请查看它提供的 谓词。例如,CLP(ℛ) 提供了 {}/1 和一些其他谓词,并且有一个专门的 语法 用于陈述包含 浮点数 (在本例中)。

其他约束求解器提供它们的自己的谓词来描述它们各自域的实体。例如,CLP(FD) 提供 (#=)/2 和一些其他谓词来推理 整数 dif/2 让您可以推理 任何 Prolog 项。等等。

从程序员的角度来看,这与使用您的 Prolog 系统的 任何其他谓词完全相同,无论它是内置的-在或源于图书馆。原则上都是一样的:

list_length(Ls, L) 这样的目标可以理解为:"The length of the list Ls is L."

{ X = A + B } 这样的目标可以理解为:数字 X 等于 A 和 [=28 的 sum =].例如,如果您使用的是 CLP(Q),很明显我们在这种情况下谈论的是 有理数

在您的第二个示例中,子句的 正文 连词 (A, B),其中 A 是 CLP(ℛ) 约束,Bfactorial(PrevN, NewF).

形式的目标

重点是:CLP(ℛ) 约束 也是 一个目标!看看:

?- write_canonical({a,b,c}).
{','(a,','(b,c))}
true.

因此,您只是使用 library(clpr) 中的 {}/1,这是它导出的谓词之一。

你是对的 PrevNNewF 属于约束 。但是,factorial(PrevN, NewF) 不是 CLP(ℛ) 实现的用于对浮点数进行推理的 迷你语言 的一部分。因此,您不能将此目标拉入 CLP(ℛ)-特定部分。

从程序员的角度来看,CLP 的一个主要吸引力在于它 完全无缝地融入 逻辑编程,以至于它实际上几乎无法与它完全不同:约束只是谓词,并像所有其他目标一样写下来。

是否将库谓词标记为 "constraint" 几乎没有任何区别:所有 谓词都可以视为约束,因为它们只能 约束答案,永远不要放松他们。

注意两个例子你post都是递归的!没关系。事实上,递归谓词很可能是您将来使用约束的 多数 情况。

然而,对于 factorial 的具体情况,您的 Prolog 系统的 CLP(FD) 约束可能更合适,因为它们完全致力于 整数 .

的推理