我正在启动 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
Run Code Online (Sandbox Code Playgroud)
我明白这段代码在做什么,但我对 Prolog 如何解析sum. 主要是,令我感到奇怪的是 . 中没有明确的“返回” sum。
我的理解是,会发生这样的事情:
A. 解释器尝试通过调用 sum 来统一规则 sum(X, [1,2,3]):
0 Sum(X, [1, 2, 3])
1 Sum(Y, [2,3]
2 Sum(Z, [3])
3 Sum(0, []) % our recursive base
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
我对其运作方式的理解是否正确?或者有没有更好的方法让我的命令式思维思考/表达上面发生的事情?
是的,你的想法是正确的。我会稍微改一下你所说的,这样可能会更清楚一些。
要理解 Prolog 的执行,首先要做的就是认识到 Prolog 就像一个弱定理证明器。它会尽力使您的查询成立。所以,当你输入查询时?- sum(X, [1,2,3]).,Prolog会尽力使其成立。在这种情况下,正如我们将看到的,它将需要绑定X到6,让我们看看如何。
你给 Prolog 证明这sum(X, [1, 2, 3])是真的的唯一元素是
sum(0, []).
Run Code Online (Sandbox Code Playgroud)
和
sum(Total, [Head|Tail]) :- sum(Sum,Tail), Total is Head + Sum.
Run Code Online (Sandbox Code Playgroud)
显然,Prolog 对第一个子句无能为力,因为它无法统一[]和[1, 2, 3]。因此它尝试使用第二个子句来证明您的查询。
然后发生的事情是它试图依次证明sum(Sum,Tail)和Total is Head + Sum。证明这两个选项中的第一个将引发递归调用,最终将使用Tail=进行调用[]。此时,Prolog 将使用您提供的第一个子句,并推断出Sumthen 0。现在它将具有Total is Head + Sum在递归的最后一步证明第二部分 ( ) 的元素。然后,递归将返回到您猜测的初始谓词。