Prolog中的指令顺序和递归

Order of instructions and recursion in 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 is Y+1”。 该行不应该是

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

在那种情况下,我们首先将 Y 设置为 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 是一种有趣的语言,因为它几乎具有时间旅行的感觉,您必须向前和向后思考才能理解程序的工作原理。

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

这意味着:如果 S 包含 Y 次出现的 A,并且 A == B,那么 [B | S] 又包含一次出现的 A.

例如,假设我们正在计算 prolog[prolog, prolog, prolog] 中出现的次数。 [B | S] = [prolog, prolog, prolog],所以 S = [prolog, prolog]Sprolog出现的次数是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] 包含 XA,则 S 又包含一次 A。这不可能。

再次使用上面的例子:显然 [A | S] = [prolog, prolog, prolog] 包含 3 次 prolog,所以 X = 3 应该成立。但是 Y 必须是 4,正文中的目标将尝试证明 S = [prolog, prolog] 包含 4prolog。显然不是这样。

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