[英]Prolog - How to get the sum of a list's elements?
我对序言很陌生,我正在尝试编写一个小程序,给定一个列表,该程序返回列表元素的总和。 遵循我所看到的所有示例,使我想到了一个类似于以下的解决方案:
addup([],0).
addup([FirstNumber | RestOfList], Total) :-
addup(RestOfList, TotalOfRest),
Total is FirstNumber + TotalOfRest.
但是,当我使用以下值测试该解决方案时:
?- addup([1,2,3,4],0).
我只是从中获得_34521之类的垃圾值。
然后,我尝试了第二个解决方案,如下所示:
sum([], 0).
sum([H|T], N):-
X is H+N,
sum(T, X).
这个可以正确地将数字相加,但是它无法将X的最终值(是正确的答案)传递给N。因此对于测试用例:
?- sum([1,2,3,4], 0).
我得到的答案是6(N的最终值)和X的倒数第二个值,而不是X(X的最终值),而不是10。有关这些解决方案都不起作用的任何帮助和/或解释都将非常有用赞赏。 谢谢。
首先,一个空列表的总和为0-这是您已经拥有的基本情况。
其次,元素H
与列表T
的总和N
是添加到H
的列表T
的总和。 序言操作上的统一,所以这表示, N
是统一的总和H
和T
,其中的总和T
是统一与X
使用sum(T,X)
sum([], 0).
sum([H|T], N):-
sum(T, X),
N is X + H.
这给出:
?- sum([1,2,3,4],N).
N = 10.
在您最初的问题中, ?- sum([1,2,3,4], 0).
实际上说“如果列表[1,2,3,4]
的总和为0
这是正确的”-您需要传递变量作为第二个参数,以使sum
与答案统一。
更多信息:
_34521
是未绑定变量的表示-表示存在一个变量,但尚未将其与值统一。
次要考虑因素:
对于适当的长列表,上面的实现将用完堆栈空间,因为必须存储递归的每一帧,以便从下往上进行添加。 为了防止出现堆栈错误,我们可以像这样使用尾递归累加器:
sum(L, N):-
sum(L, 0, N).
sum([],N,N).
sum([H|T],A,N) :-
A1 is A + H,
sum(T,A1,N).
...保留原始方法的签名,包装sum / 3。 由于规则主体中没有选择点(假设A + H对于给定的A和H始终相同,并且列表为空或不为空),因此Prolog会在离开范围时丢弃每个框架(因为没有更多操作可做),完成后将返回到原始调用者。
每个实例中sum([1,2,3],N)
简化堆栈:
非尾递归:
rest-of-stack
rest-of-stack,sum([1|[2,3]],_1001)
rest-of-stack,sum([1|[2,3]],_1001),sum([2|[3]],_1002)
rest-of-stack,sum([1|[2,3]],_1001),sum([2|[3]],_1002),sum([3|[]],_1003)
rest-of-stack,sum([1|[2,3]],_1001),sum([2|[3]],_1002),sum([3|[]],_1003),sum([],0)
rest-of-stack,sum([1|[2,3]],_1001),sum([2|[3]],_1002),sum([3|[]],3)
rest-of-stack,sum([1|[2,3]],_1001),sum([2|[3]],5)
rest-of-stack,sum([1|[2,3]],6)
rest-of-stack
尾递归:
rest-of-stack
rest-of-stack,sum([1,2,3],_1001)
rest-of-stack,sum([1|[2,3]],0,_1001)
rest-of-stack,sum([2|[3]],1,_1001)
rest-of-stack,sum([3|[]],3,_1001)
rest-of-stack,sum([],6,6)
rest-of-stack
请注意,尾递归堆栈的深度对于列表的任何长度都是有限的(取决于调用它的名称),其中非尾递归堆栈的深度与列表的长度成正比。
因此,诸如N is 10^7,length(L,N),maplist(=(1),L),sum(L,N).
的呼叫N is 10^7,length(L,N),maplist(=(1),L),sum(L,N).
(由@false引发)可能会在没有尾递归的情况下失败,并且很可能会成功。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.