Prolog中的指令顺序和递归

Posted

技术标签:

【中文标题】Prolog中的指令顺序和递归【英文标题】:Order of instructions and recursion in Prolog 【发布时间】:2022-01-10 05:53:47 【问题描述】:

我刚从 prolog 开始,我有一个关于递归的问题。

我基本上想计算某个值在列表中出现的次数, 所以我有例如:

count( a, [ a, s, d, f, g, a, s, d, a, s ], W ).  W = 3.

我想计算“a”在列表中出现的次数并将数字存储在“W”中。

正确答案是

count( _, [], 0 ). 
count( A, [B|S], X ) :- A==B, count( A, S, Y ), X is Y + 1. 
count( A, [B|S], X ) :- \+ A == B, count( A, S, X ).

但是,我不明白为什么在第 2 行中,最后是“X 是 Y+1”。 这条线不应该是

count( A, [A|S], X ) :- Y is X + 1, count( A, S, Y ).

在这种情况下,我们首先将 Y 设置为 1,然后通过递归再次将其发送到“count”。

如果有人可以帮助我,我将不胜感激!

【问题讨论】:

【参考方案1】:

请考虑当您调用时:

?- count(a,[a,s,d,f,g,a,s,d,a,s],W).

...那么第一个匹配的谓词是count(A,[B|S],X)。这意味着它看起来像count(a,[a|S],X),其中SX 是变量。 X 只是来自原始调用的W,所以它仍然是一个变量。

建议然后评估 Y is X + 1 是没有意义的,因为 X 是一个变量。

然而,原来的谓词确实有意义。

count(A,[B|S],X) :- A==B, count(A,S,Y), X is Y + 1.

当它递归时,它将一个新变量Y 发送到第二个count/3 谓词中(或者只是在第三个谓词中传递相同的变量)。它会一直这样做,直到它最终将变量统一为0 时达到基本情况。此时它展开递归,现在它终于可以执行X is Y + 1(因为Y 是一个值),因此X 现在是一个值。

Prolog 是一门有趣的语言,因为它几乎有一种时间旅行的感觉,您必须向前和向后思考才能理解程序的工作原理。

【讨论】:

哇,现在我明白了!非常感谢!【参考方案2】:
count( A, [B|S], X ) :- A==B, count( A, S, Y ), X is Y + 1.

这意味着:如果S 包含Y 出现的AA == B,则[B | S] 包含更多的A

例如,假设我们正在计算prolog[prolog, prolog, prolog] 中的出现次数。 [B | S] = [prolog, prolog, prolog],所以S = [prolog, prolog]prologS 中出现的次数是2,所以我们应该有Y = 2。在[B | S]prolog 的出现次数是3,所以我们应该有X = 3。一旦我们知道Y = 2,然后X is Y + 1 计算X 的正确值。

count( A, [A|S], X ) :- Y is X + 1, count( A, S, Y ).

这意味着:如果[A | S] 包含X 出现的A,那么S 包含更多的A。这不可能。

再次使用上面的例子:显然[A | S] = [prolog, prolog, prolog] 包含3 个prolog,所以X = 3 应该成立。但是Y 必须是 4,并且正文中的目标会尝试证明 S = [prolog, prolog] 包含 4 次出现的 prolog。显然情况并非如此。

请注意,这个解释只是关于谓词的含义。它不需要我们考虑递归、目标顺序或程序实际执行的确切方式。在进行 Prolog 编程时,首先要弄清楚程序的逻辑含义

【讨论】:

以上是关于Prolog中的指令顺序和递归的主要内容,如果未能解决你的问题,请参考以下文章

Prolog 中的子列表谓词

谓词用于返回prolog中给定列表的元素顺序的排列

Prolog Eliza 实现 - 循环和递归

如何使用有限谓词递归确定序言中的商?

Prolog:递归无法正常工作

如何在没有 DCG 的 L 系统启发的重写系统中进行递归