Recursion 理解Prolog中的递归规则

Recursion 理解Prolog中的递归规则,recursion,prolog,Recursion,Prolog,我是从Prolog开始的,这是我的荣幸,我在努力理解Prolog是如何处理递归的 给定以下代码: sum(0, []). sum(Total, [Head|Tail]) :- sum(Sum,Tail), Total is Head + Sum. % executed in the Prolog interpreter: sum(X, [1,2,3]) X = 6 我理解这段代码在做什么,但我有点不明白Prolog是如何解决sum的递归调用的。主要是,我感到奇怪的是,sum中没有明确的“re

我是从Prolog开始的,这是我的荣幸,我在努力理解Prolog是如何处理递归的

给定以下代码:

sum(0, []).
sum(Total, [Head|Tail]) :- sum(Sum,Tail), Total is Head + Sum.

% executed in the Prolog interpreter:
sum(X, [1,2,3])
X = 6
我理解这段代码在做什么,但我有点不明白Prolog是如何解决
sum
的递归调用的。主要是,我感到奇怪的是,
sum
中没有明确的“return”

我的理解是这样的事情会发生:

A.解释器试图通过调用sum:

0 Sum(X, [1, 2, 3])
1 Sum(Y, [2,3] 
2 Sum(Z, [3])
3 Sum(0, []) % our recursive base
B.一旦我们找到基本事实,它就会爬回递归“堆栈”:

3 Sum(0, []), Total = 0 % we start at our base fact
2 Sum(1, [3]), Total = 3
1 Sum(2, [2, 3]), Total = 5 
0 Sum(X, [1, 2, 3]) Total = 6 % sweet, sweet unification

我对其功能的理解是否正确?还是有更好的方法让我的命令式思维思考/表达上面发生的事情?

这是正确的。显式“return”的作用是通过在定义
sum/2
的谓词中满足空列表之和的独特方式来实现的


您可以通过在解释器处执行目标
sum(X,[])
来说服自己。

是的,您的想法是正确的。我会稍微改写一下你说的话,这样可能会更清楚一点

要理解Prolog的执行,首先要认识到Prolog就像一个弱定理证明器。它将试图使你的疑问成为现实。因此,当您输入查询
?-sum(X[1,2,3])。
时,Prolog将尽最大努力使其成为现实。在这种情况下,我们将看到,它需要将
X
绑定到
6
,让我们看看如何绑定

你给Prolog的唯一证明
sum(X[1,2,3])
为真的元素是

sum(0, []).

显然,Prolog无法处理第一个子句,因为它不能统一
[]
[1,2,3]
。因此,它试图通过使用第二个子句来证明您的查询


然后,它试图证明
sum(sum,Tail)
Total是Head+sum
。证明这两个选项中的第一个选项将导致递归调用,并最终使用
Tail
=
[]
调用它。此时,Prolog将使用您提供的第一个子句,并将推断
Sum
因此是
0
。在递归的最后一步,它现在有了证明第二部分的元素(
Total是Head+Sum
)。然后,递归被处理回您所猜测的初始谓词。

同样。。尝试运行“trace.”谓词,在主谓词之前,按enter键单步执行,您可以看到它到达递归的底部[],然后重新展开。谓词的递归调用必须“展开”才能获得总数,这一事实非常重要。一个更有效的实现可以通过为total引入一个“辅助参数”,将递归调用放在尾部递归的“last call”形式中来实现,这样可以避免在这种情况下堆栈的任何“展开”。
sum(Total, [Head|Tail]) :- sum(Sum,Tail), Total is Head + Sum.