2013-04-10 60 views
1

我在编写prolog程序,它从两个列表中总结项目并将结果呈现在另一个列表中。Prolog - 从两个列表中总结数字

例如:

列表1:

[1, 3, 4, 2] 

列表2:

[5, 1, 3, 0] 

结果:

[6, 4, 7, 2] 

到目前为止,我有这样的:

list_sum([],[],[]). 
list_sum([H1|T1],[H2|T2],L3):-list_sum(T1,T2,[X|L3]), X is H1+H2. 

?-list_sum([1,2,3,4],[1,2,3,4],R),write(R). 

回答

1

你快到了。 您的问题是,总和的结果应放在第二个子句的头部,而不是递归调用!

list_sum([H1|T1],[H2|T2],[X|L3]):-list_sum(T1,T2,L3), X is H1+H2. 

请注意,这是作为一个结果,“返回”,在你写的方式,L3是在其中您已删除从recusive通话头(X)的列表;而你的意思则相反:将元素(X)添加到结果列表中。

+0

请参阅下面的答案。 – 2013-04-10 18:35:34

+0

@NicholasCarey:同意你的最后条款,我只是想显示OPs问题并修复,而不改变他想解决的方式。我不同意你的第二和第三条款,当这些清单有不同的长度时,程序就会成功。 – gusbro 2013-04-10 18:38:37

+0

取决于要求,* n'est-ce pas *? – 2013-04-10 19:01:53

0

结果应该是一个列表,所以你不能只是说X is H1+H2因为X不是一个列表,你只用一个变量匹配列表的头部。同样的原因,list_sum([],[],0)也不正确。答案是这样的:

sum([],[],[]). 
sum([H1| T1], [H2| T2], [ResH| ResT]) :- 
     sum(T1, T2, ResT), 
     ResH is H1+H2. 

但是当你运行你自己的代码,第一个X与H1 + H2相匹配,在第二递归调用X的值,并且不能与T1 + T2的头相匹配。所以它输出一个no

2

@gusbro说什么。此外,你需要重新安排操作顺序,并添加了一些额外的特殊情况来处理不同长度的名单:

list_sum([]  , []  , [] ) . 
list_sum([]  , [Y|Ys] , [Z|Zs]) :- Z is 0+Y , list_sum([] , Ys , Zs) . 
list_sum([X|Xs] , []  , [Z|Zs]) :- Z is X+0 , list_sum(Xs , [] , Zs) . 
list_sum([X|Xs] , [Y|Ys] , [Z|Zs]) :- Z is X+Y , list_sum(Xs , Ys , Zs) . 

您需要在我的例子中移动评估(Z is X+Y)以上,使Z在之前评估递归。此完成两件事情:

  • 首先,它使谓词尾递归,这意味着该解决方案是迭代的,因此不消耗堆栈空间。在你的代码中,评估只有在整个递归完成之后才会执行。每个中间值都保存在堆栈中,并在返回的路上从右向左评估。这意味着你会把你的堆栈放在一个大的列表中。

  • 其次,在递归之前评估每个结果意味着你快速失败。第一个与结果不一致的总和不能使整个操作失败。您的解决方案失败缓慢考虑10,000,000个项目清单,其中第一个项目不会与结果清单中的第一个项目相加:您将遍历所有10,000,000个项目,然后—假设您没有打击您的筹码—您开始从右向左评估总和。你的谓词不会失败​​,直到最后一次评估。

+0

“,直到最后一次评估”......可能已经* *应该*已经非常*先*。 :)很好的回答! – 2013-04-13 10:53:43

1

它在SWI-Prolog的一个班轮:

list_sum(X,Y,S) :- maplist(plus, X,Y,S). 

它作品也'落后':

?- maplist(plus, [1,2,3],Y,[3,4,5]). 
Y = [2, 2, 2]. 
+0

Ahhh maplist :) – Ash 2016-03-30 07:23:54

0
domains 
list=integer* 
predicates 
add(list,list,list) 
clauses 
add([],[],[]). 
add([V1X|X],[V1Y|Y],[V1Z|Z]):-add(X,Y,Z),V1Z=V1X+V1Y.