2013-04-10 59 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.