任何人都可以解释prolog使用这个递归程序的步骤吗?

时间:2017-09-14 10:58:42

标签: recursion prolog

我最近开始学习prolog,但我很难处理递归规则。我理解简单的规则,但是我遇到了这个例子的问题,我发现了一个程序,它给出了列表中所有元素的总和:

addup([], 0).

addup([FirstNumber | RestOfList], Total) :-
    addup(RestOfList, TotalOfRest),   
    Total is FirstNumber + TotalOfRest.

现在如果我追踪这个,我得到以下内容:

[trace]  ?- addup([3, 5, 7], Total).
   Call: (7) addup([3, 5, 7], _G322)
   Call: (8) addup([5, 7], _L1)
   Call: (9) addup([7], _L2)
   Call: (10) addup([], _L3)
   Exit: (10) addup([], 0)    % I understand what it does till here
^  Call: (10) _L2 is 7+0
^  Exit: (10) 7 is 7+0
   Exit: (9) addup([7], 7)
^  Call: (9) _L1 is 5+7
^  Exit: (9) 12 is 5+7
   Exit: (8) addup([5, 7], 12)
^  Call: (8) _G322 is 3+12
^  Exit: (8) 15 is 3+12
   Exit: (7) addup([3, 5, 7], 15)
Total = 15.

我理解前几步;它不断削减头部并制作新的TotalOfRest,直到原始列表为空,并与第一个事实相匹配。这使得第三个TotalOfRest(我称之为_L3)等于0。 但现在呢? Prolog是如何使L2等于7 + 0的步骤。我理解prolog开始回溯,但是什么与得出结论相匹配?道达尔现在7岁了?或者有三种不同的Total&具有与TotalOfRest不同的值?并且RestofList仍然等于[]而FirstNumber仍然是7?

所以基本上:prolog如何从找出L3到最终结论?

我对此非常陌生,所以如果有人能为我解释这个问题,我会非常感激!

1 个答案:

答案 0 :(得分:2)

请注意,您的递归调用会引入一个新变量:

addup([], 0).
addup([FirstNumber | RestOfList], Total) :-
    addup(RestOfList, TotalOfRest),   
    Total is FirstNumber + TotalOfRest.

在每个递归级别,都会创建一个新的TotalOfRest变量。请注意,上层递归级别TotalRest与递归中较深的级别不一样

使用变量名称可以更方便trace

[trace]  ?- addup([3, 5, 7], Total).
   Call: (7) addup([3, 5, 7], _Total)
   Call: (8) addup([5, 7], _TotalOfRest1)
   Call: (9) addup([7], _TotalOfRest2)
   Call: (10) addup([], _TotalOfRest3)
   Exit: (10) addup([], 0)
^  Call: (10) _TotalOfRest2 is 7+0
^  Exit: (10) 7 is 7+0
   Exit: (9) addup([7], 7)
^  Call: (9) _TotalOfRest1 is 5+7
^  Exit: (9) 12 is 5+7
   Exit: (8) addup([5, 7], 12)
^  Call: (8) _Total is 3+12
^  Exit: (8) 15 is 3+12
   Exit: (7) addup([3, 5, 7], 15)
Total = 15.

所以,如果执行递归调用,则会创建一个新变量_TotalOfRest1。调用以递归方式完成,直到_TotalOfRest3。现在,在该级别_TotalOfRest3 = 0设置为0。但是递归中仍然存在需要解决的命令:Total is FirstNumber + TotalOfRest.。请注意,所有这些Total都是局部变量(这也适用于TotalOfRestFirstNumber)。所以在每个级别都解决了这个问题。请注意,例如递归级别为2的Total对于调用者来说实际上是_TotalOfRest2

所以递归看起来像:

addup([3, 5, 7], Total) :-
    % FirstNumber = 3
    % RestOfList = [5, 7]
    % Total = Total
    addup([5,7], _TotalOfRest1) :-
         % FirstNumber = 5
         % RestOfList = [7]
         % Total = _TotalOfRest1
         addup([7], _TotalOfRest2) :-
             % FirstNumber = 7
             % RestOfList = []
             % Total = _TotalOfRest2
             addup([],_TotalOfRest3),
             % resolved to _TotalOfRest3 = 0
             Total is 7 + 0.
             % resolved to Total = 7
         % resolved to _TotalOfRest2 = 7
         Total is 5 + 7.
         % resolved to Total = 12
     % resolved to _TotalOfRest1 = 12
     Total is 3 + 12.
     % resolved to Total = 15
% resolved tot Total = 15

代码部分以粗体显示,您可以看到在每个级别都有局部变量接地并传回外部范围。