您可以将其pow
视为一个分为处理不同参数值的两个子句的函数。该函数是递归的,由第二个子句中的递归调用触发。但是在这个电话之后,还有事情要做,Z is Z1*1
目标。这些“悬空”计算是在递归终止并再次控制向上的“气泡”时完成的,可以说是在返回的路上。(这种递归有一个名字,我不记得了)。
看看这个注释跟踪:
[trace] ?- pow(2,2,X).
% initial call
Call: (6) pow(2, 2, _G368) ? creep
% the second clause is picked for this call,
% the third argument is an uninstantiated variable, represented by _G368
Call: (7) _G444 is 2+ -1 ? creep
% the first goal in this claus is "Y1 is Y -1", which is here
% translated with its bindings
Exit: (7) 1 is 2+ -1 ? creep
% the is/2 goal has been called, and has provided a binding for "Y1"
Call: (7) pow(2, 1, _G443) ? creep
% this is the first recursive call, with the new arguments 2, 1 and an
% undefined Z1
Call: (8) _G447 is 1+ -1 ? creep
% again the second clause is used, this is the first goal in it,
% calling is/2
Exit: (8) 0 is 1+ -1 ? creep
% is/2 delivers a binding for the current Y1, 0
Call: (8) pow(2, 0, _G446) ? creep
% the next (second) recursive call; see how at this point non of the
% "Z is Z1*X" "statements" have been reached
Exit: (8) pow(2, 0, 1) ? creep
% the second recursive call matches the first clause; this is where
% the base case is used! it can immediately "Exit" as with the match
% to the clause all bindings have been established already; the third
% argument is instantiated to 1
Call: (8) _G450 is 1*2 ? creep
% now the recursion has terminated, and control is passed back to that
% more recent calling clause (this was the one where Y1 has been bound
% to 0); now the "Z is Z1*X" can be tried for the first time, and Z
% can be instantiated ("unified")
Exit: (8) 2 is 1*2 ? creep
% this is the result of this unification, Z is bound to 2;
% with this, this level in the stack of recursive calls has been completed...
Exit: (7) pow(2, 1, 2) ? creep
% ... and this is the result ("Exit") of this call, showing all
% instantiated parameters
Call: (7) _G368 is 2*2 ? creep
% but this just brings us back one more level in the call stack, to a
% pending execution (this was the one where Y1 has been bound to 1),
% now the pending execution can be performed
Exit: (7) 4 is 2*2 ? creep
% here you see the result of the execution of is/2, binding Z to 4
Exit: (6) pow(2, 2, 4) ? creep
% and this finishes the initial call of the predicate, delivering a
% binding for the X in the query, 4; you can tell that the recursive
% call stack as been processed completely by looking at the "stack
% depth indicator", (6), which matches the initial (6) when the trace
% started (they don't necessarily start with 0 or 1).