total_item([],0).
total_item([_|Rest],N) :- total_item(Rest,C), N is C+1.
该程序将数组作为输入并计算该列表中的项目总数。但是我没有得到确切的变量N和C存储的内容。任何解释将不胜感激。谢谢
答案 0 :(得分:2)
向后阅读:
total_item([], 0).
total_item
映射0
到[]
(关联这两个)。
total_item([_ | Rest], N) :-
total_item( Rest, C ),
N is C + 1 .
将C
映射到Rest
,将C+1
映射到[_ | Rest]
-列表比列表Rest
长一个元素。
以生成方式工作的最通用查询可以看到此信息:
2 ?- total_item(L, C).
L = [],
C = 0 ;
L = [_G1464],
C = 1 ;
L = [_G1464, _G1467],
C = 2 ;
L = [_G1464, _G1467, _G1470],
C = 3 ;
L = [_G1464, _G1467, _G1470, _G1473],
C = 4 .
答案 1 :(得分:2)
Ness的答案将为您提供对该谓词定义的清晰理解。但是,您可以从中学到更多。让我们跟踪一个简单的调用。在这里,我使用的是GNU Prolog,但大多数Prolog系统提供相同的跟踪功能:
| ?- trace.
The debugger will first creep -- showing everything (trace)
yes
{trace}
| ?- total_item([1,2,3], N).
1 1 Call: total_item([1,2,3],_285) ?
2 2 Call: total_item([2,3],_354) ?
3 3 Call: total_item([3],_378) ?
4 4 Call: total_item([],_402) ?
4 4 Exit: total_item([],0) ?
5 4 Call: _430 is 0+1 ?
5 4 Exit: 1 is 0+1 ?
3 3 Exit: total_item([3],1) ?
6 3 Call: _459 is 1+1 ?
6 3 Exit: 2 is 1+1 ?
2 2 Exit: total_item([2,3],2) ?
7 2 Call: _285 is 2+1 ?
7 2 Exit: 3 is 2+1 ?
1 1 Exit: total_item([1,2,3],3) ?
N = 3
(1 ms) yes
您可以在前四行中看到谓词导致遍历列表直到结束,然后 我们计算出待处理 N is C + 1
目标。列表中的每个元素都会产生一个未决的算术评估目标。必须将这些未完成的目标存储在 stack 中,直到对total_item /2
谓词的递归调用终止为止。结果,计算大小为N的列表的长度需要与N成正比的空间(用于堆栈)。该谓词定义不是 tail-recursive 。
但是我们可以重写谓词,通过使用累加器使其成为 tail-recursive 来提高其空间复杂度。累加器是一个参数,用于存储中间结果,在这种情况下,该结果到目前为止是列表中元素数量的计数:
total_item(List, Total) :-
total_item(List, 0, Total).
total_item([], Total, Total).
total_item([_| Rest], Total0, Total) :-
Total1 is Total0 + 1,
total_item(Rest, Total1, Total).
让我们追寻相同的目标:
| ?- total_item([1,2,3], N).
1 1 Call: total_item([1,2,3],_285) ?
2 2 Call: total_item([1,2,3],0,_285) ?
3 3 Call: _382 is 0+1 ?
3 3 Exit: 1 is 0+1 ?
4 3 Call: total_item([2,3],1,_285) ?
5 4 Call: _435 is 1+1 ?
5 4 Exit: 2 is 1+1 ?
6 4 Call: total_item([3],2,_285) ?
7 5 Call: _488 is 2+1 ?
7 5 Exit: 3 is 2+1 ?
8 5 Call: total_item([],3,_285) ?
8 5 Exit: total_item([],3,3) ?
6 4 Exit: total_item([3],2,3) ?
4 3 Exit: total_item([2,3],1,3) ?
2 2 Exit: total_item([1,2,3],0,3) ?
1 1 Exit: total_item([1,2,3],3) ?
N = 3
(1 ms) yes
请注意,累加器(辅助total_item/3
谓词中的第二个参数)如何随着列表的增加而增加。有了这个定义,就没有悬而未决的目标,这意味着空间复杂度是O(1)而不是O(N)。好多了。